todo/Zapret2/circular.md
loop-uh 737f065567 Вики переехала на wiki2.zapret.moe: домен заменён во всём хранилище
wiki.zapret.moe заблокирован в России, читатели до редиректа не доходят. Во всех заметках, плашках [!mirror], ссылках и скриптах домен заменён на wiki2.zapret.moe; в AGENTS.md записано правило — ссылаться только на wiki2. Скрипт статистики считает своими заходы с обоих доменов. Чужие незакоммиченные правки в nuc/ в коммит не попали — только замена домена.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:15:27 -04:00

150 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
description: "Справочник Lua-оркестратора circular в Zapret 2: автопереключение стратегий десинхронизации при RST и ретрансмиссиях, параметры и примеры."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/Zapret2/circular](https://wiki2.zapret.moe/Zapret2/circular)
# circular — оркестратор циклического переключения стратегий
`circular` — Lua-оркестратор, который автоматически переключает стратегию десинхронизации при обнаружении неудач (RST, ретрансмиссии, HTTP-редирект DPI).
**Требует** перехвата входящего трафика (`--in-range`) для детектирования RST и HTTP-ответов.
---
## Синтаксис
```
--lua-desync=circular[:param=val[:...]]
--lua-desync=<func>:strategy=1[:final]
--lua-desync=<func>:strategy=2
...
```
Каждый подчинённый инстанс **обязан** иметь `strategy=N`, где N начинается с 1 без пропусков.
---
## Параметры circular
| Параметр | Описание | По умолчанию |
|---|---|---|
| `fails=N` | Порог неудач для переключения стратегии | `3` |
| `time=N` | Сбросить счётчик неудач, если последняя была > N секунд назад | `60` |
| `failure_detector=func` | Имя кастомной Lua-функции детектора неудач | `standard_failure_detector` |
| `success_detector=func` | Имя кастомной Lua-функции детектора успеха | `standard_success_detector` |
| `hostkey=func` | Имя кастомной функции генератора ключа хоста | `standard_hostkey` |
| `key=string` | Имя таблицы в `autostate` — изоляция состояния между несколькими `circular` | автоматически |
| `nld=N` | Обрезать hostname до N-уровневого домена (`static.a.google.com` → `google.com` при `nld=2`) | без обрезки |
| `reqhost` | Не работать, если hostname неизвестен (только IP) | выкл. |
---
## Параметры на подчинённых инстансах
| Параметр | Описание |
|---|---|
| `strategy=N` | **Обязательно.** Номер стратегии, начиная с 1, без пропусков |
| `final` | Финальная стратегия — ротация на ней останавливается |
---
## Параметры standard_failure_detector
Передаются прямо в `circular` (не в подчинённые инстансы).
### TCP
| Параметр | Описание | По умолчанию |
|---|---|---|
| `retrans=N` | Кол-во ретрансмиссий = неудача | `3` |
| `maxseq=N` | Считать ретрансмиссии только до этой relative sequence | `32768` |
| `reset` | Слать RST ретрансмиттеру (ускоряет разрыв зависшего соединения) | выкл. |
| `inseq=N` | Входящий RST считается неудачей только до этой rseq | `4096` |
| `no_rst` | Отключить триггер по входящему RST | выкл. |
| `no_http_redirect` | Отключить триггер по HTTP-редиректу DPI | выкл. |
### UDP
| Параметр | Описание | По умолчанию |
|---|---|---|
| `udp_out=N` | Неудача если исходящих пакетов >= N | `4` |
| `udp_in=N` | Неудача если входящих пакетов <= N | `1` |
---
## Параметры standard_success_detector
| Параметр | Описание | По умолчанию |
|---|---|---|
| `maxseq=N` | TCP: если исходящая rseq > N — соединение успешно | `32768` |
| `inseq=N` | TCP: если входящая rseq > N — соединение успешно | `4096` |
| `udp_in=N` | UDP: если входящих пакетов > N — успех | `1` |
---
## Стратегия из нескольких фаз
Одна стратегия может включать **несколько инстансов** с одинаковым `strategy=N`.
`circular` проходит весь план и выполняет **все** инстансы, у которых номер совпадает — по порядку.
```bash
--lua-desync=circular:fails=1:time=300
--lua-desync=fake:blob=fake_default_http:repeats=4:strategy=1 # фаза 1
--lua-desync=multisplit:pos=2:seqovl=211:strategy=1 # фаза 2
--lua-desync=multidisorder:pos=host:strategy=2:final
```
Для стратегии 1 последовательно выполнятся `fake` → `multisplit`.
### Форматирование в config
Параметры внутри `NFQWS2_OPT="..."` можно переносить на новые строки и делать отступы — shell разбирает их как обычные пробелы:
```bash
NFQWS2_OPT="
--filter-tcp=443 --filter-l7=tls <HOSTLIST> --payload=tls_client_hello
--out-range=-d1000
--in-range=-s5556
--lua-desync=circular:fails=1:time=300:retrans=3:nld=2
--lua-desync=fake:blob=fake_default_http:repeats=4:strategy=1
--lua-desync=multisplit:pos=2:seqovl=211:strategy=1
--lua-desync=multidisorder:pos=host:strategy=2:final
--new
"
```
---
## Пример
```
--in-range=-s5556
--out-range=-d1000
--lua-desync=circular:fails=1:time=300:retrans=3:nld=2
--lua-desync=multisplit:pos=2:strategy=1
--lua-desync=fake:blob=fake_default_http:strategy=2
--lua-desync=multidisorder:pos=host:strategy=3:final
```
- `fails=1` — переключить стратегию после 1 неудачи
- `time=300` — сбросить счётчик если последняя неудача была > 5 мин назад
- `retrans=3` — неудача = 3 ретрансмиссии
- `nld=2` — ключ хоста = 2-уровневый домен (`google.com`)
- `final` на стратегии 3 — остановить ротацию на ней
---
## Как работает
![[wiki-anim-z2-circular.svg|Анимация: circular после неудачи переключает стратегию 1, 2, 3; на final ротация останавливается]]
1. Пакет приходит в `circular` с `ctx`
2. `circular` берёт план (все подчинённые инстансы) и отменяет нормальный цикл C
3. Проверяет детектор неудач/успеха для текущего соединения
4. Если неудач >= `fails` — переходит к следующей стратегии `(N % total) + 1`
5. Если достигнута `final`-стратегия — ротация останавливается
6. Выполняет **только** инстансы с `strategy=текущая`
Состояние (номер стратегии, счётчик неудач) хранится **per-host** в глобальной таблице `autostate` и переживает отдельные соединения.