101 lines
15 KiB
Markdown
101 lines
15 KiB
Markdown
# B1 Проверка ядра и внешних зависимостей
|
||
|
||
Дата: 2026-02-27
|
||
Статус: draft
|
||
Владелец: Engineering
|
||
|
||
## 1) Цель
|
||
- Убедиться, что Go-ядро имеет централизованную логику для работы с nftables, policy routing, systemd, cgroup и SmartDNS, и что эти зависимости отражены в конфигурациях/документации.
|
||
- Выявить потенциальные отверстия (например, части логики, которые напрямую обращаются к shell-скриптам `routes_update`, `autoloop`, `trace`) перед тем, как стартовать задачи для веба.
|
||
|
||
## 2) Критерии завершения
|
||
- Описание работы ключевых модулей ({`routes_update.go`, `traffic_mode.go`, `events_bus.go`, `watchers.go`, `resolver.go`, `smartdns_runtime.go`, `vpn_handlers.go`}) подготовлено, включая внешние зависимости (nftables, SmartDNS, systemd, AdGuard VPN API).
|
||
- Сформулирован список требований (root, обязательные сервисы, долгие операции, возможные блокировки) на случай запуска через веб-консоль.
|
||
- Уточнено, какие данные уже сохраняются в `stateDir`, `appmark` и `routes` файлах, чтобы веб мог отображать информацию без дополнительного API.
|
||
|
||
## 3) Задачи
|
||
- Пройти `routes_update.go`, `routes_units.go`, `routes_cache.go`, `nft_update.go` и описать, как обновляются маршруты и кэшируются состояния.
|
||
- Проанализировать `traffic_mode.go`, `traffic_appmarks.go`, `traffic_app_profiles.go`, `traffic_audit.go`: что именно меняют (fwmark, cgroup, nft sets) и какие проверки выполняются.
|
||
- Прописать взаимодействие с DNS/SmartDNS (`dns_settings.go`, `smartdns_runtime.go`, `smartdns_wildcards_store.go`, `resolver.go`), включая init/restore/caching жизненный цикл.
|
||
- Проверить `watchers.go`, `events_bus.go`, `trace_handlers.go`: какие события стримятся, какие веб-интерфейсы они смогут потреблять, и нужны ли дополнительные фильтры или буферизация.
|
||
- Отметить, какие части кода требуют root-доступ и как это влияет на веб (например, API будет работать под сервис-аккаунтом и выполнять nft/update через internal API, но сама служба должна запускаться с нужными привилегиями).
|
||
- Собрать стартовый список фактов по каждому модулю: с какими `systemd` unit'ами, `nft` set'ами, SmartDNS/AdGuard VPN API и `stateDir` работает, и какие ограничения это накладывает.
|
||
- Задокументировать потенциальные точки отказа (недоступность nftables/systemd, SmartDNS/AdGuard API) и предложить стратегию контроля ошибок для веб-интерфейса.
|
||
|
||
## 4) Модули и зависимости
|
||
|
||
### `routes_update.go`
|
||
- Основной контроллер обновления маршрутов: строит policy routes, nftables-цепочки `agvpn`/`agvpn4`/`agvpn_dyn4`, запускает `runResolverJob`, пишет список доменов/IP в `stateDir` и сохраняет `status.json`.
|
||
- Поддерживает прогресс через `events.push("routes_nft_progress", ...)`, пишет heartbeat-файлы и требует доступа к `iproute2`, `nft`, `stateDir`, `trace.log` и воркеру резольвера.
|
||
- Обрабатывает `force`/`auto` конфигурации из `TrafficModeState` и фиксирует `trafficEval` в статусе, что важно для отображения в вебе.
|
||
|
||
### `routes_units.go`, `routes_cache.go`, `nft_update.go`
|
||
- `routes_units.go` разрешает `systemd` имя (`routesServiceUnitName`, `routesTimerUnitName`) и используется в `/routes/service`/`timer`.
|
||
- `routes_cache.go` кеширует `domains`, `ips`, `domains` state; можно использовать для расчёта прогресса и восстановления.
|
||
- `nft_update.go` держит “умный” апдейтер, который управляет правилами и sets; важно документировать, какие команды выполняются и как проверяется успех (`runNFTUpdate`, `progressCb`) для веба.
|
||
|
||
### `traffic_mode.go` + `traffic_appmarks*`
|
||
- Управляют состоянием (`stateDir/state-traffic-mode.json`), применяют флаги fwmark и policy rules (`applyTrafficMode`), читают/пишут список принудительных субнетов/UID/cgroup.
|
||
- `traffic_appmarks.go` работает с cgroup v2, создаёт маркеры `MARK_APP`/`MARK_DIRECT` и задаёт TTL (через systemd scopes) для runtime управления per-app traffic.
|
||
- `traffic_app_profiles.go` хранит профили в `stateDir` и предоставляет CRUD, что пригодится вебу для создания shortcut-профилей.
|
||
- `traffic_audit.go` проверяет состояние nft/route и формирует `TrafficAudit` issues, полезные для мониторинга.
|
||
|
||
### `dns_settings.go` + `resolver.go`
|
||
- Хранит конфигурацию `dns-upstreams.conf`, режим (`dns_mode.json`) и pool upstreams; отвечает за benchmark, SmartDNS control (`smartdns` service start/stop) и режим `ViaSmartDNS`.
|
||
- `resolver.go` запускает Go-резольвер, читает `domains.txt`, `meta-special.txt`, `static-ips.txt`, использует кеши (`domain-cache.json`, `ptr-cache.json`) и пишет результат в `stateDir`.
|
||
- Сервисы SmartDNS (`smartdns_runtime.go`, `smartdns_wildcards_store.go`) управляют дополнительными wildcard-базами, runtime stats и prewarm, что потребует отображения статуса SmartDNS в веб.
|
||
|
||
### `vpn_handlers.go` + `vpn_login_session.go`
|
||
- Интеграция с AdGuard VPN API: `autoloop`, `autoconnect`, `locations`, `set location`, `logout` и status založený na HTTP-запросах к локальному `adguardvpn` сервису.
|
||
- `vpn_login_session.go` создаёт PTY-сессию (через `runCommand` + `systemd-run --user`?), сохраняет состояния в `loginStatePath` и выпускает события (`events.push`) для SSE; вебу потребуется поддерживать эти пользователи.
|
||
|
||
### `events_bus.go`, `watchers.go`, `trace_handlers.go`
|
||
- `startWatchers` запускает наблюдение за `status.json`, `loginState`, autoloop логом, `trace.log`, state traffic appmarks TTL и systemd unitами (routes service/timer, VPN unit, SmartDNS).
|
||
- Все watcher-изменения отправляются в `events` и поступают клиенту через `handleEventsStream`, что даёт вебу источник realtime данных.
|
||
- `trace_handlers.go` читает `trace.log`, `trace-json` и принимает append, что позволяет вебу показывать live trace и записывать дополнительные строки.
|
||
|
||
### `routes_handlers.go`
|
||
- Управление systemd-unit'ами (`routes_service`, `routes_timer`), ручной rollback/clear, fixing policy route, переключение режимов/advanced config.
|
||
- Служит фасадом для CLI (как `routes-update`, `routes-clear`, `autoloop`), следовательно API может использоваться как `POST /api/v1/routes/service` и `POST /api/v1/routes/update`.
|
||
|
||
### Корневые ограничения и привилегии
|
||
- `routes_update`/`routes_handlers` запускаются как root (nft, ip, systemctl); веб-интерфейс должен вызывать API, а не повторять команды, сохраняя сервис privileged.
|
||
- SmartDNS требует запуска `smartdns-local.service`; VPN команды ждут доступ к AdGuard VPN (возможно, `adguardvpn.service`).
|
||
- `stateDir` и `domains` файлы должны быть доступны API, а вебу важно понять, какие endpoints кешируют/читают эти файлы. Например, `routes timer enable` хранится в `routes_timer_state.json`.
|
||
- Потенциальные точки отказа:
|
||
- `nft` команды падут, если kernel не поддерживает nftables или service не запущен — API должен возвращать `CmdResult` с `stderr` и `exitCode`.
|
||
- `systemd` unit может быть недоступна (не установлен `routes-service`), мониторинг через watchers должен отправлять `unit_state_changed`.
|
||
- SmartDNS runtime может не стартовать: нужно отразить ошибку через `events.push("smartdns_error"... )` и вернуть `CmdResult.ok=false`.
|
||
- AdGuard VPN API или PTY могут быть недоступны; API должен возвращать ошибки и веб должен приступать к повторной попытке.
|
||
|
||
## 5) Матрица зависимостей
|
||
|
||
| Модуль | http/cli | Зависимости | Состояния/файлы | Потенциальные ошибки |
|
||
| --- | --- | --- | --- | --- |
|
||
| `events_bus.go`, `watchers.go`, `events_handlers.go` | `/api/v1/events/stream` | in-memory queue, watcher goroutines | `status.json`, `login_state.json`, `trace.log`, systemd unit polling, `autoloop.log` | SSE disconnected, poll errors, buffer overflow |
|
||
| `routes_update.go` | `POST /api/v1/routes/update`, CLI `routes-update` | `iproute2`, `nft`, `runResolverJob`, `SmartDNS` | `stateDir/{domains,ips}*`, `status.json`, `trace.log`, `heartbeat` | Нет VPN-интерфейса, резольвер падает, `nft` пишет ошибки |
|
||
| `routes_units.go` | `/api/v1/routes/service`, `/routes/timer`, CLI `routes-clear` | `systemd` (service/timer names) | `routes_timer_state.json`, unit name env | Unit не установлена, systemctl возвращает error |
|
||
| `routes_cache.go`, `nft_update.go` | внутренняя логика routes update | `nft`, temp files | `/var/run/selective-vpn` temp files | `nft` прогресс в stderr, temp-файлы не создаются |
|
||
| `traffic_mode.go` + `traffic_appmarks*` | `/api/v1/traffic/*` | `nft`, policy routing, `cgroup v2`, `systemd` | `stateDir/traffic-mode.json`, `appmarks.json`, cgroup scopes | Некорректная конфигурация, `nft` не применяет правила |
|
||
| `traffic_app_profiles.go` | `/api/v1/traffic/app-profiles` | файловые операции | `stateDir/app-profiles.json` | Файл повреждён, не сохраняется |
|
||
| `dns_settings.go` + `resolver.go` | `/api/v1/dns-*` | `resolv.conf`, SmartDNS binary | `dns-upstreams.conf`, `dns_mode.json`, `domain-cache.json`, `ptr-cache.json` | Нет upstream, benchmark таймаут |
|
||
| `smartdns_runtime.go`, `smartdns_wildcards_store.go` | `/api/v1/smartdns/*` | `smartdns-local.service`, wildcard files | `smartdns.conf`, `wildcards.json` | Service fail, wildcard file read-only |
|
||
| `vpn_handlers.go`, `vpn_login_session.go` | `/api/v1/vpn/*` | AdGuard VPN API, PTY, systemd-user | `login_state.json`, `autoloop.log` | API недоступен, PTY не стартует |
|
||
| `trace_handlers.go` | `/api/v1/trace*` | доступ к `trace.log` | `trace.log` | Файл недоступен, append write error |
|
||
|
||
Эта матрица показывает, какие компоненты требуют привилегий и как ошибка отражается на UI. В Phase D можно перенести эти строки в таблицу `web-ready` и отметить `status` (готово/требует/blocked).
|
||
|
||
### Технические state-файлы и кеши
|
||
- `stateDir` (по умолчанию `/var/lib/selective-vpn`) содержит:
|
||
- `domains.txt`, `ips-*.txt`, `ipmap-*.txt` — сериализация выходных данных resolver, используются trace/expand logic.
|
||
- `state-traffic-mode.json`, `appmarks.json`, `app-profiles.json` — основные состояния traffic mode/appmarks/profiles, читаются `traffic_mode.go`, `traffic_appmarks.go`, `traffic_app_profiles.go`.
|
||
- `domain-cache.json`, `ptr-cache.json` — кеш resolver, обновляется из `runResolverJob` и влияет на `routes_update` (limit/ttl).
|
||
- `status.json`, `heartbeat` — пишутся `routes_update`. `watchStatusFile` читает file, `events.push("status_changed")` доставляет web info (`iface`, `table`, `healthy`).
|
||
- `login_state.json` — создаётся `vpn_login_session.go`, SSE `login_state_changed` отражает current state; при `CmdResult.ok=false` пишется `error` в file/event.
|
||
- `trace.log` — задействован `trace_handlers.go` и `watchFileChange`, SSE `trace_changed` парсит tail. `trace_append` endpoint пишет новые строки (CmdResult). Web должна ограничить size (<=1<<20) и показывать stderr/exitCode.
|
||
|
||
### Watchers и события
|
||
- `watchStatusFile`, `watchLoginFile`, `watchAutoloop`, `watchTrafficAppMarksTTL`, `watchSystemdUnit*` запускаются на `startWatchers` и публикуют события (`status_changed`, `login_state_changed`, `autoloop_status_changed`, `unit_state_changed`, `appmarks_ttl`).
|
||
- `events_bus` буферизует последние `SVPN_EVENTS_CAP` событий (config via env). SSE `events/stream` читает их `since`/`Last-Event-ID`. При ошибок (blocked mutex, dropped events) нужно логировать `selective-vpn-api` и отображать `status_error`.
|
||
- `events.push` используется для `routes_nft_progress`, `smartdns`, `trace_changed`. Вебу важно знать ключи, чтобы фильтровать события по статус/trace/health.
|