mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-16 14:58:17 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de8845b89d | ||
|
|
f1eae764ab | ||
|
|
03c650b33c | ||
|
|
64b12c51e5 | ||
|
|
2d8e031904 | ||
|
|
28f0cd6e73 | ||
|
|
9a9179a23b | ||
|
|
48123bf1f7 | ||
|
|
ece4e52676 | ||
|
|
1d24d1e040 | ||
|
|
d0fd6b4868 | ||
|
|
328408fa30 | ||
|
|
0343bb248d | ||
|
|
e4dd1574b8 | ||
|
|
1e3486ee14 | ||
|
|
efe7470732 | ||
|
|
8acd5690f4 | ||
|
|
c2e3176a46 | ||
|
|
658252d46a | ||
|
|
5aaf7b3d6c | ||
|
|
031ac7616d | ||
|
|
098417d19f | ||
|
|
2f0a74a11e | ||
|
|
40c37c3448 | ||
|
|
77fb530120 | ||
|
|
faa0274521 | ||
|
|
8a253d3d95 |
@@ -93,9 +93,15 @@ v0.7
|
||||
|
||||
v0.7.1
|
||||
|
||||
* init.d: fix non-working incoming redirect
|
||||
* init.d: nft fix non-working incoming redirect
|
||||
* nfqws2: cancel reasm if server window size is smaller than expected reasm size
|
||||
* nfqws2: add EOL at the end of truncated buffered DLOG line if it's too large. increase log line buffer
|
||||
* nfqws2: autohostlist reset fail counter if udp_in > threshold
|
||||
* nfqws2: reduced default retrans maxseq to 32768
|
||||
* nfqws2: solved inability to get SSID using nl80211 on kernels 5.19+
|
||||
|
||||
v0.7.2
|
||||
|
||||
* zapret-lib: fix broken is_retransmission()
|
||||
* zapret-auto: add success detector logic
|
||||
* nfqws2: clean lua cutoff on profile change
|
||||
|
||||
373
docs/manual.md
373
docs/manual.md
@@ -796,8 +796,8 @@ nfqws2 следит за превышением верхней границы с
|
||||
|
||||
```
|
||||
--filter-tcp=80,443 --filter-l7=http,tls
|
||||
--out-range=-d10
|
||||
--in-range=-s1 --lua-desync=circular
|
||||
--out-range=-s34228 and
|
||||
--in-range=-s5556 --lua-desync=circular
|
||||
--in-range=x
|
||||
--payload=tls_client_hello
|
||||
--lua-desync=fake:blob=fake_default_tls:badsum:strategy=1
|
||||
@@ -811,12 +811,373 @@ nfqws2 следит за превышением верхней границы с
|
||||
|
||||
* Профильный фильтр по tcp портам и типу протокола потока позволяет избежать вызовов LUA на другом трафике.
|
||||
Профиль вообще не будет задействован, если условия фильтра не выполнятся.
|
||||
* `--out-range` указан, чтобы отсечь поток от LUA по исходящему направлению после 10 отправленных пакетов с данными - для экономии процессора.
|
||||
На Linux может быть не нужно, если используется фильтр connbytes.
|
||||
* Инстанс circular для своей работы требует начальные входящие пакеты потока, а по умолчанию они отключены.
|
||||
Поэтому включаем вплоть до первого пакета с данными tcp, который имеет relative sequence 1.
|
||||
* `--out-range` указан, чтобы отсечь поток от LUA по исходящему направлению после relative sequence (32768+1460) - для экономии процессора.
|
||||
Такое значение выбрано из-за специфики функции circular - значение s32768 используется в детекторе успеха как порог срабатывания по умолчанию,
|
||||
1460 - максимально возможная длина данных в tcp пакете. На Linux может быть не нужно, если используется фильтр connbytes.
|
||||
* сircular для своей работы требует начальные входящие пакеты потока, а по умолчанию они отключены.
|
||||
Поэтому включаем вплоть до позиции relative sequence 5556. По умолчанию детектор успеха реагирует на s4096. Добавлен еще 1 пакет макс 1460 байт.
|
||||
* Остальные инстансы не нуждаются во входящем трафике. Снова отключаем. Действие `--in-range=x` распространяется до конца профиля.
|
||||
* Действие `--payload` распространяется на два следующих за ним инстанса.
|
||||
* Строчка `--lua-desync=fake:blob=fake_default_tls:badsum:strategy=1` вызывает функцию `fake` с 3 аргументами : `blob`, `badsum`, `strategy`.
|
||||
Значением аргумента `badsum` является пустая строка.
|
||||
|
||||
## Прототип LUA функции
|
||||
|
||||
Стандартная LUA функция имеет прототип
|
||||
|
||||
`function desync_f(ctx,desync)`
|
||||
|
||||
* ctx - контекст для вызова некоторых C функций
|
||||
* desync - таблица, содержащая все передаваемые значения, включая аргументы, диссект текущего пакета и т.д.
|
||||
|
||||
Функция возвращает вердикт по текущему пакету - VERDICT_PASS, VERDICT_MODIFY, VERDICT_DROP.
|
||||
Может не возвращать ничего, тогда результат приравниваться к VERDICT_PASS.
|
||||
|
||||
* VERDICT_PASS передает пакет как есть без учета изменений диссекта
|
||||
* VERDICT_MODIFY выполняет реконструкцию и отправку текущего диссекта
|
||||
* VERDICT_DROP дропает текущий пакет
|
||||
|
||||
Результат всех lua-desync инстансов аггрегируется : VERDICT_MODIFY замещает VERDICT_PASS, VERDICT_DROP замещает их обоих.
|
||||
|
||||
### Структура таблицы desync
|
||||
|
||||
Лучше всего изучать структуру desync по ее реальному содержимому, выполняя тестовую desync функцию pktdebug из zapret-lib.lua.
|
||||
|
||||
<details>
|
||||
<summary><b>Пакет http-req от запроса по ipv6 к http://one.one.one.one</b></summary>
|
||||
<pre>
|
||||
desync:
|
||||
.target
|
||||
.port
|
||||
number 80
|
||||
.ip6
|
||||
string 26 06 47 00 47 00 00 00 00 00 00 00 00 00 10 01
|
||||
.func
|
||||
string pktdebug
|
||||
.func_n
|
||||
number 1
|
||||
.profile_n
|
||||
number 1
|
||||
.l7payload
|
||||
string http_req
|
||||
.dis
|
||||
.tcp
|
||||
.th_dport
|
||||
number 80
|
||||
.th_x2
|
||||
number 0
|
||||
.th_off
|
||||
number 8
|
||||
.th_sum
|
||||
number 18781
|
||||
.th_win
|
||||
number 64
|
||||
.options
|
||||
.1
|
||||
.kind
|
||||
number 1
|
||||
.2
|
||||
.kind
|
||||
number 1
|
||||
.3
|
||||
.data
|
||||
string 30 40 18 9A 6F A5 3E 89
|
||||
.kind
|
||||
number 8
|
||||
.th_seq
|
||||
number 19930989
|
||||
.th_ack
|
||||
number 1489231977
|
||||
.th_flags
|
||||
number 24
|
||||
.th_urp
|
||||
number 0
|
||||
.th_sport
|
||||
number 48118
|
||||
.ip6
|
||||
.ip6_flow
|
||||
number 1871905881
|
||||
.ip6_hlim
|
||||
number 64
|
||||
.ip6_dst
|
||||
string 26 06 47 00 47 00 00 00 00 00 00 00 00 00 10 01
|
||||
.exthdr
|
||||
.ip6_plen
|
||||
number 110
|
||||
.ip6_src
|
||||
string 1A E5 18 81 E1 CD E8 24 BA 16 39 FF FE 8A DE 12
|
||||
.ip6_nxt
|
||||
number 6
|
||||
.payload
|
||||
string 47 45 54 20 2F 20 48 54 54 50 2F 31 2E 31 0D 0A 48 6F 73 74 3A 20 6F 6E 65 2E 6F 6E 65 2E 6F 6E 65 2E 6F 6E 65 0D 0A 55 73 65 72 2D 41 67 65 6E 74 3A 20 63 75 72 6C 2F 38 2E 38 2E 30 0D 0A 41 63 63 65 70 74 3A 20 2A 2F 2A 0D 0A 0D 0A
|
||||
.l4proto
|
||||
number 6
|
||||
.transport_len
|
||||
number 110
|
||||
.reasm_offset
|
||||
number 0
|
||||
.reasm_data
|
||||
string 47 45 54 20 2F 20 48 54 54 50 2F 31 2E 31 0D 0A 48 6F 73 74 3A 20 6F 6E 65 2E 6F 6E 65 2E 6F 6E 65 2E 6F 6E 65 0D 0A 55 73 65 72 2D 41 67 65 6E 74 3A 20 63 75 72 6C 2F 38 2E 38 2E 30 0D 0A 41 63 63 65 70 74 3A 20 2A 2F 2A 0D 0A 0D 0A
|
||||
.ifout
|
||||
string eth0
|
||||
.fwmark
|
||||
number 0
|
||||
.func_instance
|
||||
string pktdebug_1_1
|
||||
.replay
|
||||
boolean false
|
||||
.track
|
||||
.pos
|
||||
.dt
|
||||
number 0.013066192
|
||||
.server
|
||||
.tcp
|
||||
.pos
|
||||
number 1
|
||||
.rseq
|
||||
number 1
|
||||
.scale
|
||||
number 13
|
||||
.mss
|
||||
number 1360
|
||||
.winsize_calc
|
||||
number 65535
|
||||
.uppos
|
||||
number 0
|
||||
.seq0
|
||||
number 1489231976
|
||||
.seq
|
||||
number 1489231977
|
||||
.uppos_prev
|
||||
number 0
|
||||
.winsize
|
||||
number 65535
|
||||
.pcounter
|
||||
number 1
|
||||
.pdcounter
|
||||
number 0
|
||||
.pbcounter
|
||||
number 0
|
||||
.client
|
||||
.tcp
|
||||
.pos
|
||||
number 79
|
||||
.rseq
|
||||
number 1
|
||||
.scale
|
||||
number 10
|
||||
.mss
|
||||
number 1380
|
||||
.winsize_calc
|
||||
number 65536
|
||||
.uppos
|
||||
number 79
|
||||
.seq0
|
||||
number 19930988
|
||||
.seq
|
||||
number 19930989
|
||||
.uppos_prev
|
||||
number 0
|
||||
.winsize
|
||||
number 64
|
||||
.pcounter
|
||||
number 3
|
||||
.pdcounter
|
||||
number 1
|
||||
.pbcounter
|
||||
number 78
|
||||
.reverse
|
||||
.tcp
|
||||
.pos
|
||||
number 1
|
||||
.rseq
|
||||
number 1
|
||||
.scale
|
||||
number 13
|
||||
.mss
|
||||
number 1360
|
||||
.winsize_calc
|
||||
number 65535
|
||||
.uppos
|
||||
number 0
|
||||
.seq0
|
||||
number 1489231976
|
||||
.seq
|
||||
number 1489231977
|
||||
.uppos_prev
|
||||
number 0
|
||||
.winsize
|
||||
number 65535
|
||||
.pcounter
|
||||
number 1
|
||||
.pdcounter
|
||||
number 0
|
||||
.pbcounter
|
||||
number 0
|
||||
.direct
|
||||
.tcp
|
||||
.pos
|
||||
number 79
|
||||
.rseq
|
||||
number 1
|
||||
.scale
|
||||
number 10
|
||||
.mss
|
||||
number 1380
|
||||
.winsize_calc
|
||||
number 65536
|
||||
.uppos
|
||||
number 79
|
||||
.seq0
|
||||
number 19930988
|
||||
.seq
|
||||
number 19930989
|
||||
.uppos_prev
|
||||
number 0
|
||||
.winsize
|
||||
number 64
|
||||
.pcounter
|
||||
number 3
|
||||
.pdcounter
|
||||
number 1
|
||||
.pbcounter
|
||||
number 78
|
||||
.lua_state
|
||||
.hostname
|
||||
string one.one.one.one
|
||||
.hostname_is_ip
|
||||
boolean false
|
||||
.lua_in_cutoff
|
||||
boolean true
|
||||
.lua_out_cutoff
|
||||
boolean false
|
||||
.t_start
|
||||
number 1700000000
|
||||
.incoming_ttl
|
||||
number 51
|
||||
.l7proto
|
||||
string http
|
||||
.arg
|
||||
.testarg1
|
||||
string val1
|
||||
.testarg2
|
||||
string val2
|
||||
.tcp_mss
|
||||
number 1360
|
||||
.l7proto
|
||||
string http
|
||||
.outgoing
|
||||
boolean true
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
|
||||
| Поле | Тип | Содержание | Примечание |
|
||||
|:------|:-----|:-------------|:-----------|
|
||||
| func | string | имя desync функции | |
|
||||
| func_n | number | номер инстанса внутри профиля | |
|
||||
| func_instance | string | название инстанса | производная имени функции, номера инстанса и номера профиля |
|
||||
| profile_n | number | номер профиля | |
|
||||
| profile_name | string | название профиля | может отсутствовать |
|
||||
| template_n | number | номер шаблона, на базе которого создан профиль | может отсутствовать |
|
||||
| template_name | string | название шаблона, на базе которого создан профиль | может отсутствовать |
|
||||
| cookie | string | значение параметра nfqws2 --cookie для профиля | может отсутствовать |
|
||||
| outgoing | bool | true , если направление исходящее | |
|
||||
| ifin | string | имя входящего интерфейса | может отсутствовать |
|
||||
| ifout | string | имя исходящего интерфейса | может отсутствовать |
|
||||
| fwmark | number | fwmark текущего пакета | только в Linux |
|
||||
| target | table | таблица, включающая ip адрес и порт, на базе которых проверяются ipset-ы и фильтры по портам | |
|
||||
| replay | bool | проигрывание задержанного пакета (replay) | |
|
||||
| replay_piece | number | номер проигрываемой части | нумерация с 1 |
|
||||
| replay_piece_count | number | количество проигрываемых частей| |
|
||||
| replay_piece_last | bool | последняя проигрываемая часть | |
|
||||
| l7payload | string | тип пейлоада текущего пакета или группы пакетов | если неизвестно - unknown |
|
||||
| l7proto | string | тип протокола потока | если неизвестно - unknown |
|
||||
| reasm_data | string | результат сборки многопакетного сообщения, либо сам пейлоад, если сборки не было | пока применяется только для tcp |
|
||||
| reasm_offset | string | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp |
|
||||
| decrypt_data | string | результат сборки и дешифровки пейлоада или пейлоадов нескольких пакетов | применяется для quic |
|
||||
| tcp_mss | number | MSS противоположного конца tcp соединения | только для tcp |
|
||||
| track | table | данные, привязанные к записи conntrack | только если есть conntrack, может не быть |
|
||||
| arg | table | все аргументы инстанса и их значения | подстановки % и # уже замещены |
|
||||
| dis | table | диссект текущего пакета | |
|
||||
|
||||
### Структура диссекта
|
||||
|
||||
Диссект включает в себя поля ip, ip6, tcp, udp.
|
||||
ip присутствует в случае ipv4, ip6 - в случае ipv6.
|
||||
По наличиню ip или ip6 можно определить версию ip протокола.
|
||||
По наличию tcp или udp можно определять L4 протокол.
|
||||
|
||||
Сами таблицы хедеров копируют названия полей C структур из `netinet/{ip,ip6,tcp,udp}.h`.
|
||||
ip адреса и ipv4 options передаются как raw string.
|
||||
Для преобразования raw ip в текстовую форму можно использовать C функцию ntop. Она определяет версию ip автоматически по размеру.
|
||||
ipv6 extension headers и tcp options представляются в форме таблиц.
|
||||
|
||||
Все числовые многобайтовые значения автоматически переведены из network byte order в machine byte order.
|
||||
|
||||
**ip**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| ip_v | версия ip - 4 |
|
||||
| ip_hl | длина ip заголовка в блоках по 4 байта. 5 без ip options. |
|
||||
| ip_tos | type of service. содержит DSCP |
|
||||
| ip_len | полная длина ip пакета вместе со всеми заголовками и пейлоадом |
|
||||
| ip_id | идентификация пакета для сборки из фрагментов |
|
||||
| ip_off | offset фрагмента, флаги MF (more fragments) и DF (dont fragment) |
|
||||
| ip_ttl | time to live - максимальное количество хопов |
|
||||
| ip_p | [номер ip протокола](https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml). как правило IPPROTO_TCP или IPPROTO_UDP |
|
||||
| ip_sum | чексумма ip хедера |
|
||||
| ip_src | ip источника |
|
||||
| ip_src | ip назначения |
|
||||
| options | бинарный блок ip options (практически не используется, режется всеми) |
|
||||
|
||||
**ip6**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| ip6_flow | первые 4 байта ipv6 header : version (6), traffic class, flow label |
|
||||
| ip6_plen | длина пакета за вычетом базового хедера ipv6 - IP6_BASE_LEN (40) байт |
|
||||
| ip6_nxt | [следующий протокол](https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml). если нет exthdr - IPPROTO_TCP (6) или IPPROTO_UDP (17) |
|
||||
| ip6_hlim | hop limit. имеет тот же смысл, что и TTL в ipv4 |
|
||||
| ip6_src | ipv6 адрес источника |
|
||||
| ip6_dst | ipv6 адрес приемника |
|
||||
| exthdr | массив таблиц расширенных хедеров (индекс от 1) |
|
||||
|
||||
**ip6 exthdr**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| type | [тип хедера](https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) : IPPROTO_HOPOPTS, IPPROTO_ROUTING, IPPROTO_DSTOPTS, IPPROTO_MH, IPPROTO_HIP, IPPROTO_SHIM6, IPPROTO_FRAGMENT, IPPROTO_AH |
|
||||
| next | тип следующего хедера. аналогично type. для последнего хедера может быть IPPROTO_TCP или IPPROTO_UDP |
|
||||
| data | данные без первых двух байтов - типа и длины |
|
||||
|
||||
**udp**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| uh_sport | порт источника |
|
||||
| uh_dport | порт приемника |
|
||||
| uh_ulen | длина udp - header UDP_BASE_LEN (8) + длина пейлоада |
|
||||
| uh_sum | чексумма udp |
|
||||
|
||||
**tcp**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| th_sport | порт источника |
|
||||
| th_dport | порт приемника |
|
||||
| th_x2 | зарезервированное поле. используется для расширенных tcp flags |
|
||||
| th_off | размер tcp хедера в блоках по 4 байта |
|
||||
| th_flags | tcp флаги : TH_FIN,TH_SYN,TH_RST,TH_PUSH,TH_ACK,TH_FIN,TH_URG,THE_ECE,TH_CWR |
|
||||
| th_seq | sequence number |
|
||||
| th_ack | acknowledgement number |
|
||||
| th_win | размер tcp окна |
|
||||
| th_sum | чексумма tcp |
|
||||
| th_urp | urgent pointer |
|
||||
| options | массив таблиц [tcp опций](https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml) (индекс от 1) |
|
||||
|
||||
**tcp options**
|
||||
| Поле | Описание |
|
||||
|:------|:-----|
|
||||
| kind | [тип опции](https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml) : TCP_KIND_END, TCP_KIND_NOOP, TCP_KIND_MSS, TCP_KIND_SCALE, TCP_KIND_SACK_PERM, TCP_KIND_SACK, TCP_KIND_TS, TCP_KIND_MD5, TCP_KIND_AO, TCP_KIND_FASTOPEN |
|
||||
| data | блок данных опции без kind и length. отсутствует для TCP_KIND_END и TCP_KIND_NOOP |
|
||||
|
||||
|
||||
### Структура track
|
||||
|
||||
|
||||
@@ -1,20 +1,49 @@
|
||||
-- standard automation/orchestration code
|
||||
-- this is related to making dynamic strategy decisions without rewriting or altering strategy function code
|
||||
-- orchestrators can decide which instances to call or not to call or pass them dynamic arguments
|
||||
-- failure detectors test potential block conditions for orchestrators
|
||||
-- failure and success detectors test potential block conditions for orchestrators
|
||||
|
||||
-- standard host key generator for per-host storage
|
||||
-- arg: reqhost - require hostname, do not work with ip
|
||||
-- arg: key - a string - table name inside autostate table. to allow multiple orchestrator instances to use single host storage
|
||||
function automate_host_record(desync)
|
||||
local hostkey, askey
|
||||
if desync.arg.reqhost then
|
||||
hostkey = desync.track and desync.track.hostname
|
||||
else
|
||||
hostkey = host_or_ip(desync)
|
||||
-- arg: nld=N - cut hostname to N level domain. NLD=2 static.intranet.microsoft.com => microsoft.com
|
||||
function standard_hostkey(desync)
|
||||
local hostkey = desync.track and desync.track.hostname
|
||||
if hostkey then
|
||||
if desync.arg.nld and tonumber(desync.arg.nld)>0 then
|
||||
-- dissect_nld returns nil if domain is invalid or does not have this NLD
|
||||
-- fall back to original hostkey if it fails
|
||||
local hktemp = dissect_nld(hostkey, tonumber(desync.arg.nld))
|
||||
if hktemp then
|
||||
hostkey = hktemp
|
||||
end
|
||||
end
|
||||
elseif not desync.arg.reqhost then
|
||||
hostkey = host_ip(desync)
|
||||
end
|
||||
-- prevent nld for ip addresses
|
||||
return hostkey
|
||||
end
|
||||
|
||||
-- per-host storage
|
||||
-- arg: key - a string - table name inside autostate table. to allow multiple orchestrator instances to use single host storage
|
||||
-- arg: hostkey - hostkey generator function name
|
||||
function automate_host_record(desync)
|
||||
local hostkey, hkf, askey
|
||||
|
||||
if desync.arg.hostkey then
|
||||
if type(_G[desync.arg.hostkey])~="function" then
|
||||
error("automate: invalid hostkey function '"..desync.arg.hostkey.."'")
|
||||
end
|
||||
hkf = _G[desync.arg.hostkey]
|
||||
else
|
||||
hkf = standard_hostkey
|
||||
end
|
||||
hostkey = hkf(desync)
|
||||
if not hostkey then
|
||||
DLOG("automate: host record key unavailable")
|
||||
return nil
|
||||
end
|
||||
|
||||
askey = (desync.arg.key and #desync.arg.key>0) and desync.arg.key or desync.func_instance
|
||||
DLOG("automate: host record key 'autostate."..askey.."."..hostkey.."'")
|
||||
if not autostate then
|
||||
@@ -28,6 +57,7 @@ function automate_host_record(desync)
|
||||
end
|
||||
return autostate[askey][hostkey]
|
||||
end
|
||||
-- per-connection storage
|
||||
function automate_conn_record(desync)
|
||||
if not desync.track.lua_state.automate then
|
||||
desync.track.lua_state.automate = {}
|
||||
@@ -65,6 +95,13 @@ function automate_failure_counter(hrec, crec, fails, maxtime)
|
||||
end
|
||||
return false
|
||||
end
|
||||
-- resets failure counter if it has started counting
|
||||
function automate_failure_counter_reset(hrec)
|
||||
if hrec.failure_counter then
|
||||
DLOG("automate: failure counter reset")
|
||||
hrec.failure_counter = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- location is url compatible with Location: header
|
||||
-- hostname is original hostname
|
||||
@@ -78,6 +115,18 @@ function is_dpi_redirect(hostname, location)
|
||||
return false
|
||||
end
|
||||
|
||||
function standard_detector_defaults(arg)
|
||||
return {
|
||||
inseq = tonumber(arg.inseq) or 4096,
|
||||
retrans = tonumber(arg.retrans) or 3,
|
||||
maxseq = tonumber(arg.maxseq) or 32768,
|
||||
udp_in = tonumber(arg.udp_in) or 1,
|
||||
udp_out = tonumber(arg.udp_out) or 4,
|
||||
no_http_redirect = arg.no_http_redirect,
|
||||
no_rst = arg.no_rst
|
||||
}
|
||||
end
|
||||
|
||||
-- standard failure detector
|
||||
-- works with tcp and udp
|
||||
-- detected failures:
|
||||
@@ -85,46 +134,34 @@ end
|
||||
-- incoming http redirection
|
||||
-- outgoing retransmissions
|
||||
-- udp too much out with too few in
|
||||
-- arg: seq=<rseq> - tcp: if packet is beyond this relative sequence number treat this connection as successful. default is 64K
|
||||
-- arg: maxseq=<rseq> - tcp: test retransmissions only within this relative sequence. default is 32K
|
||||
-- arg: retrans=N - tcp: retrans count threshold. default is 3
|
||||
-- arg: rst=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 1
|
||||
-- arg: inseq=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K
|
||||
-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger
|
||||
-- arg: no_rst - tcp: disable incoming RST trigger
|
||||
-- arg: udp_out - udp: >= outgoing udp packets. default is 4
|
||||
-- arg: udp_in - udp: with <= incoming udp packets. default is 1
|
||||
function standard_failure_detector(desync, crec, arg)
|
||||
if crec.nocheck then return false end
|
||||
|
||||
local seq_rst = tonumber(arg.rst) or 1
|
||||
local retrans = tonumber(arg.retrans) or 3
|
||||
local maxseq = tonumber(arg.seq) or 0x10000
|
||||
local udp_in = tonumber(arg.udp_in) or 1
|
||||
local udp_out = tonumber(arg.udp_out) or 4
|
||||
|
||||
function standard_failure_detector(desync, crec)
|
||||
local arg = standard_detector_defaults(desync.arg)
|
||||
local trigger = false
|
||||
if desync.dis.tcp then
|
||||
local seq = pos_get(desync,'s')
|
||||
if maxseq and seq>maxseq then
|
||||
DLOG("standard_failure_detector: s"..seq.." is beyond s"..maxseq..". treating connection as successful")
|
||||
crec.nocheck = true
|
||||
return false
|
||||
end
|
||||
|
||||
if desync.outgoing then
|
||||
if #desync.dis.payload>0 and retrans and (crec.retrans or 0)<retrans then
|
||||
if #desync.dis.payload>0 and arg.retrans and arg.maxseq>0 and seq<=arg.maxseq and (crec.retrans or 0)<arg.retrans then
|
||||
if is_retransmission(desync) then
|
||||
crec.retrans = crec.retrans and (crec.retrans+1) or 1
|
||||
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..retrans)
|
||||
trigger = crec.retrans>=retrans
|
||||
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..arg.retrans)
|
||||
trigger = crec.retrans>=arg.retrans
|
||||
end
|
||||
end
|
||||
else
|
||||
if seq_rst and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then
|
||||
trigger = seq<=seq_rst
|
||||
if not arg.no_rst and arg.inseq>0 and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 and seq>=1 then
|
||||
trigger = seq<=arg.inseq
|
||||
if b_debug then
|
||||
if trigger then
|
||||
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..seq_rst)
|
||||
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..arg.inseq)
|
||||
else
|
||||
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..seq_rst)
|
||||
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..arg.inseq)
|
||||
end
|
||||
end
|
||||
elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then
|
||||
@@ -143,13 +180,13 @@ function standard_failure_detector(desync, crec, arg)
|
||||
end
|
||||
elseif desync.dis.udp then
|
||||
if desync.outgoing then
|
||||
if udp_out then
|
||||
local udp_in = udp_in or 0
|
||||
trigger = desync.track.pos.direct.pcounter>=udp_out and desync.track.pos.reverse.pcounter<=udp_in
|
||||
if arg.udp_out>0 then
|
||||
local pos_out = pos_get(desync,'n',false)
|
||||
local pos_in = pos_get(desync,'n',true)
|
||||
trigger = pos_out>=arg.udp_out and pos_in<=arg.udp_in
|
||||
if trigger then
|
||||
crec.nocheck = true
|
||||
if b_debug then
|
||||
DLOG("standard_failure_detector: udp_out "..desync.track.pos.direct.pcounter..">="..udp_out.." udp_in "..desync.track.pos.reverse.pcounter.."<="..udp_in)
|
||||
DLOG("standard_failure_detector: arg.udp_out "..pos_out..">="..arg.udp_out.." arg.udp_in "..pos_in.."<="..arg.udp_in)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -158,17 +195,101 @@ function standard_failure_detector(desync, crec, arg)
|
||||
return trigger
|
||||
end
|
||||
|
||||
-- standard success detector
|
||||
-- success means previous failures were temporary and counter should be reset
|
||||
-- detected successes:
|
||||
-- tcp: outgoing seq is beyond 'maxseq' and maxseq>0
|
||||
-- tcp: incoming seq is beyond 'inseq' and inseq>0
|
||||
-- udp: incoming packets count > `udp_in` and `udp_out`>0
|
||||
-- arg: maxseq=<rseq> - tcp: success if outgoing relative sequence is beyond this value. default is 32K
|
||||
-- arg: inseq=<rseq> - tcp: success if incoming relative sequence is beyond this value. default is 4K
|
||||
-- arg: udp_out - udp : must be nil or >0 to test udp_in
|
||||
-- arg: udp_in - udp: if number if incoming packets > udp_in it means success
|
||||
function standard_success_detector(desync, crec)
|
||||
local arg = standard_detector_defaults(desync.arg)
|
||||
if desync.dis.tcp then
|
||||
local seq = pos_get(desync,'s')
|
||||
if desync.outgoing then
|
||||
if arg.maxseq>0 and seq>arg.maxseq then
|
||||
DLOG("standard_success_detector: outgoing s"..seq.." is beyond s"..arg.maxseq..". treating connection as successful")
|
||||
return true
|
||||
end
|
||||
else
|
||||
if arg.inseq>0 and seq>arg.inseq then
|
||||
DLOG("standard_success_detector: incoming s"..seq.." is beyond s"..arg.inseq..". treating connection as successful")
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif desync.dis.udp then
|
||||
if not desync.outgoing then
|
||||
local pos = pos_get(desync,'n')
|
||||
if arg.udp_out>0 and pos>arg.udp_in then
|
||||
if b_debug then
|
||||
DLOG("standard_success_detector: arg.udp_in "..pos..">"..arg.udp_in)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- calls success and failure detectors
|
||||
-- resets counter if success is detected
|
||||
-- increases counter if failure is detected
|
||||
-- returns true if failure counter exceeds threshold
|
||||
function automate_failure_check(desync, hrec, crec)
|
||||
if crec.nocheck then return false end
|
||||
|
||||
local failure_detector, success_detector
|
||||
if desync.arg.failure_detector then
|
||||
if type(_G[desync.arg.failure_detector])~="function" then
|
||||
error("automate: invalid failure detector function '"..desync.arg.failure_detector.."'")
|
||||
end
|
||||
failure_detector = _G[desync.arg.failure_detector]
|
||||
else
|
||||
failure_detector = standard_failure_detector
|
||||
end
|
||||
if desync.arg.success_detector then
|
||||
if type(_G[desync.arg.success_detector])~="function" then
|
||||
error("automate: invalid success detector function '"..desync.arg.success_detector.."'")
|
||||
end
|
||||
success_detector = _G[desync.arg.success_detector]
|
||||
else
|
||||
success_detector = standard_success_detector
|
||||
end
|
||||
|
||||
if success_detector(desync, crec) then
|
||||
crec.nocheck = true
|
||||
DLOG("automate: success detected")
|
||||
automate_failure_counter_reset(hrec)
|
||||
return false
|
||||
end
|
||||
if failure_detector(desync, crec) then
|
||||
crec.nocheck = true
|
||||
DLOG("automate: failure detected")
|
||||
local fails = tonumber(desync.arg.fails) or 3
|
||||
local maxtime = tonumber(desync.arg.time) or 60
|
||||
return automate_failure_counter(hrec, crec, fails, maxtime)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- circularily change strategy numbers when failure count reaches threshold ('fails')
|
||||
-- works with tcp only
|
||||
-- this orchestrator requires redirection of incoming traffic to cache RST and http replies !
|
||||
-- each orchestrated instance must have strategy=N arg, where N starts from 1 and increment without gaps
|
||||
-- if 'final' arg is present in an orchestrated instance it stops rotation
|
||||
-- arg: fails=N - failture count threshold. default is 3
|
||||
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.
|
||||
-- arg: reqhost - pass with no tampering if hostname is unavailable
|
||||
-- arg: detector - failure detector function name.
|
||||
-- arg: success_detector - success detector function name
|
||||
-- arg: failure_detector - failure detector function name
|
||||
-- args for failure detector - see standard_failure_detector or your own detector
|
||||
-- test case: nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s1 --lua-desync=circular --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
|
||||
-- args for success detector - see standard_success_detector or your own detector
|
||||
-- test case: nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s34228 --lua-desync=circular --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
|
||||
function circular(ctx, desync)
|
||||
local function count_strategies(hrec)
|
||||
if not hrec.ctstrategy then
|
||||
@@ -223,26 +344,11 @@ function circular(ctx, desync)
|
||||
local verdict = VERDICT_PASS
|
||||
if hrec.final~=hrec.nstrategy then
|
||||
local crec = automate_conn_record(desync)
|
||||
local fails = tonumber(desync.arg.fails) or 3
|
||||
local maxtime = tonumber(desync.arg.time) or 60
|
||||
local failure_detector
|
||||
if desync.arg.detector then
|
||||
if type(_G[desync.arg.detector])~="function" then
|
||||
error("circular: invalid failure detector function '"..desync.arg.detector.."'")
|
||||
end
|
||||
failure_detector = _G[desync.arg.detector]
|
||||
else
|
||||
failure_detector = standard_failure_detector
|
||||
end
|
||||
if failure_detector(desync,crec,desync.arg) then
|
||||
-- failure happened. count failures.
|
||||
if automate_failure_counter(hrec, crec, fails, maxtime) then
|
||||
-- counter reaches threshold. circular strategy change
|
||||
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
||||
DLOG("circular: rotate strategy to "..hrec.nstrategy)
|
||||
if hrec.nstrategy == hrec.final then
|
||||
DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.")
|
||||
end
|
||||
if automate_failure_check(desync, hrec, crec) then
|
||||
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
||||
DLOG("circular: rotate strategy to "..hrec.nstrategy)
|
||||
if hrec.nstrategy == hrec.final then
|
||||
DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -298,7 +298,7 @@ function pos_str(desync, pos)
|
||||
return pos.mode..pos_get(desync, pos.mode)
|
||||
end
|
||||
function is_retransmission(desync)
|
||||
return desync.track and desync.track.tcp and 0==bitand(u32add(desync.track.tcp.uppos_orig_prev, -desync.track.tcp.pos_orig), 0x80000000)
|
||||
return desync.track and desync.track.pos.direct.tcp and 0==bitand(u32add(desync.track.pos.direct.tcp.uppos_prev, -desync.track.pos.direct.tcp.pos), 0x80000000)
|
||||
end
|
||||
|
||||
-- prepare standard rawsend options from desync
|
||||
@@ -1236,12 +1236,16 @@ function genhost(len, template)
|
||||
end
|
||||
end
|
||||
|
||||
-- return hostname if present or ip address in text form otherwise
|
||||
-- return ip addr of target host in text form
|
||||
function host_ip(desync)
|
||||
return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6)
|
||||
end
|
||||
-- return hostname of target host if present or ip address in text form otherwise
|
||||
function host_or_ip(desync)
|
||||
if desync.track and desync.track.hostname then
|
||||
return desync.track.hostname
|
||||
end
|
||||
return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6)
|
||||
return host_ip(desync)
|
||||
end
|
||||
|
||||
function is_absolute_path(path)
|
||||
|
||||
@@ -975,6 +975,23 @@ static void setup_direction(
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_changed(t_ctrack *ctrack)
|
||||
{
|
||||
if (ctrack)
|
||||
{
|
||||
if (ctrack->b_lua_in_cutoff)
|
||||
{
|
||||
DLOG("clearing lua in cutoff because of profile change\n");
|
||||
ctrack->b_lua_in_cutoff = false;
|
||||
}
|
||||
if (ctrack->b_lua_out_cutoff)
|
||||
{
|
||||
DLOG("clearing lua out cutoff because of profile change\n");
|
||||
ctrack->b_lua_out_cutoff = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t dpi_desync_tcp_packet_play(
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
|
||||
uint32_t fwmark,
|
||||
@@ -1342,6 +1359,7 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
if (!dp) goto pass_reasm_cancel;
|
||||
if (dp != dp_prev)
|
||||
{
|
||||
dp_changed(ctrack_replay);
|
||||
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
|
||||
}
|
||||
}
|
||||
@@ -1786,6 +1804,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
goto pass_reasm_cancel;
|
||||
if (dp != dp_prev)
|
||||
{
|
||||
dp_changed(ctrack_replay);
|
||||
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
#ifdef __linux__
|
||||
#define DPI_DESYNC_FWMARK_DEFAULT 0x40000000
|
||||
#else
|
||||
#elif defined(SO_USER_COOKIE)
|
||||
#define DPI_DESYNC_FWMARK_DEFAULT 512
|
||||
#else
|
||||
#define DPI_DESYNC_FWMARK_DEFAULT 0
|
||||
#endif
|
||||
|
||||
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, const uint8_t *data_pkt, size_t len_pkt, uint8_t *mod_pkt, size_t *len_mod_pkt);
|
||||
|
||||
Reference in New Issue
Block a user