Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-16 14:58:17 +00:00

27 Commits

Author SHA1 Message Date
bol-van
de8845b89d zapret-auto: separate hostkey function 2025-12-14 18:14:42 +03:00
bol-van
f1eae764ab nfqws2: clean lua cutoff on profile change 2025-12-14 17:39:15 +03:00
bol-van
03c650b33c nfqws2: set fwmark to 0 in windows 2025-12-14 16:34:10 +03:00
bol-van
64b12c51e5 update docs 2025-12-14 16:28:43 +03:00
bol-van
2d8e031904 update docs 2025-12-14 16:26:56 +03:00
bol-van
28f0cd6e73 update docs 2025-12-14 16:19:24 +03:00
bol-van
9a9179a23b update docs 2025-12-14 16:18:36 +03:00
bol-van
48123bf1f7 update docs 2025-12-14 15:03:24 +03:00
bol-van
ece4e52676 update docs 2025-12-14 15:01:51 +03:00
bol-van
1d24d1e040 zapret-auto: update comment 2025-12-14 13:29:39 +03:00
bol-van
d0fd6b4868 update docs 2025-12-14 13:27:12 +03:00
bol-van
328408fa30 zapret-auto: deduplicate standard detector defaults 2025-12-14 13:20:28 +03:00
bol-van
0343bb248d zapret-auto: unify automate dlog prefix 2025-12-14 13:02:23 +03:00
bol-van
e4dd1574b8 zapret-auto: change function name 2025-12-14 13:00:39 +03:00
bol-van
1e3486ee14 zapret-auto: add success detector logic 2025-12-14 12:33:08 +03:00
bol-van
efe7470732 update docs 2025-12-13 23:48:26 +03:00
bol-van
8acd5690f4 update docs 2025-12-13 23:46:33 +03:00
bol-van
c2e3176a46 update docs 2025-12-13 23:44:27 +03:00
bol-van
658252d46a update docs 2025-12-13 23:43:06 +03:00
bol-van
5aaf7b3d6c update docs 2025-12-13 23:42:00 +03:00
bol-van
031ac7616d update docs 2025-12-13 23:41:16 +03:00
bol-van
098417d19f update docs 2025-12-13 23:40:43 +03:00
bol-van
2f0a74a11e update docs 2025-12-13 23:39:16 +03:00
bol-van
40c37c3448 update docs 2025-12-13 23:37:51 +03:00
bol-van
77fb530120 update docs 2025-12-13 23:36:52 +03:00
bol-van
faa0274521 update docs 2025-12-13 23:35:21 +03:00
bol-van
8a253d3d95 update docs 2025-12-13 23:34:36 +03:00
6 changed files with 569 additions and 71 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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");
}
}

View File

@@ -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);