baseline: api+gui traffic mode + candidates picker

Snapshot before app-launcher (cgroup/mark) work; ignore binaries/backups.
This commit is contained in:
beckline
2026-02-14 15:32:25 +03:00
parent 50e2999cad
commit 10a10f44a8
55 changed files with 16488 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
Инструкция 3 (safe-версия)
Цель:
Сделать улучшения резолвера без risky-переписывания, сохранить обратную совместимость с текущим GUI/API,
и убрать главные источники шума: массовые NXDOMAIN, таймауты и нечитабельные метрики.
--------------------------------------------------------------------
0) Что подтверждено по текущему состоянию
--------------------------------------------------------------------
1. Основной рабочий код сейчас в:
- app/resolver.go
- app/routes_update.go
- app/dns_settings.go
- app/domains_handlers.go
2. Логи показывают:
- много NXDOMAIN (ожидаемо при широком base x subs)
- заметную долю timeout
- один агрегированный счетчик dns_errors, из-за чего трудно понять причину деградации.
3. Формат dns upstream у нас: host#port (например 94.140.14.15#53 или 127.0.0.1#6053).
Это важно: нельзя использовать валидацию, которая принимает только host:port.
--------------------------------------------------------------------
1) Архитектурное решение (рекомендуемое)
--------------------------------------------------------------------
Не оставлять только переключатель direct <-> smartdns.
Сделать 3 режима резолвера:
- direct:
обычные домены через default/meta upstream.
- smartdns:
все домены через SmartDNS address.
- hybrid_wildcard (recommended):
только wildcard-домены через SmartDNS, остальные напрямую через default/meta.
Почему так лучше:
- сохраняем скорость и отказоустойчивость direct для обычных доменов;
- wildcard-логику держим строго в SmartDNS, как ты и хотел;
- не ломаем текущий UX: можно оставить старый bool и маппить его на mode.
--------------------------------------------------------------------
2) Что НЕ внедряем из старой инструкция3
--------------------------------------------------------------------
1. Не используем netip.ParseAddrPort для upstream-валидации (ломает host#port).
2. Не используем netip.MustParseAddr в hot path (может паниковать).
3. Не добавляем лишний semaphore поверх worker pool (сложность без явной выгоды).
4. Не делаем агрессивный рефактор API-контрактов без backward-compat.
--------------------------------------------------------------------
3) Пакет безопасных правок (приоритет P1)
--------------------------------------------------------------------
P1.1 - Режимы DNS (backward compatible)
Файлы:
- app/types.go
- app/dns_settings.go
- app/routes_update.go
- app/resolver.go
Изменения:
1) Ввести enum режима:
type DNSResolverMode string
const (
DNSModeDirect DNSResolverMode = "direct"
DNSModeSmartDNS DNSResolverMode = "smartdns"
DNSModeHybrid DNSResolverMode = "hybrid_wildcard"
)
2) Расширить DNSMode/DNSStatusResponse/DNSModeRequest полем Mode,
но оставить ViaSmartDNS для старого GUI:
- если Mode пустой, использовать ViaSmartDNS:
- true -> smartdns
- false -> direct
3) В ResolverOpts передавать Mode и список wildcard-доменов (один раз на job).
4) В resolveHostGo выбирать dnsList так:
- mode == smartdns: []{smartdnsAddr}
- mode == hybrid_wildcard и host совпал с wildcard: []{smartdnsAddr}
- иначе: meta или default по текущей логике.
Примечание:
Wildcard-список уже хранится в smartdns-wildcards.json через /api/v1/smartdns/wildcards.
Нужно только использовать его в резолвере.
P1.2 - Upstream fallback с классификацией ошибок
Файл:
- app/resolver.go
Изменения:
1) В digA:
- идти по upstream последовательно;
- timeout/temporary -> fallback на следующий upstream;
- nxdomain -> остановить попытки для домена (дальше пробовать бессмысленно).
2) Классифицировать ошибки через net.DNSError + fallback по тексту:
- nxdomain
- timeout
- temporary
- other
3) Вместо одного dns_errors вести структуру счетчиков:
dns_attempts, dns_ok, dns_nxdomain, dns_timeout, dns_temporary, dns_other.
P1.3 - Разделенные метрики в summary
Файл:
- app/resolver.go
Изменения:
1) Обновить финальный лог "resolve summary" с раздельными счетчиками DNS-ошибок.
2) Добавить per-upstream агрегаты (минимум attempts/ok/timeout/nxdomain/other).
Формат может быть одной строкой JSON, чтобы GUI/анализатору было проще парсить.
P1.4 - Ограничение domain expansion
Файл:
- app/routes_update.go
Изменения:
1) Добавить конфиг-лимиты через env:
- RESOLVE_SUBS_PER_BASE_LIMIT (например default 25)
- RESOLVE_DOMAINS_HARD_CAP (например default 12000)
2) После построения domainSet:
- сортировать домены;
- при превышении hard cap обрезать хвост детерминированно;
- писать явный warning в trace.
3) Логировать breakdown:
bases_count, subs_count, expanded_count, total_domains.
--------------------------------------------------------------------
4) Пакет улучшений P2 (после P1)
--------------------------------------------------------------------
P2.1 - Negative cache
Файл:
- app/resolver.go
Идея:
- кэшировать nxdomain/servfail на короткий TTL (например 10-20 минут),
чтобы не долбить одинаковые несуществующие имена каждую прогонку.
P2.2 - PTR retry (ограниченный)
Файл:
- app/resolver.go
Идея:
- для digPTR сделать 1-2 retry только на timeout/temporary;
- не ретраить nxdomain.
P2.3 - GUI/API отображение режима
Файлы GUI:
- selective-vpn-gui/api_client.py
- selective-vpn-gui/dashboard_controller.py
- selective-vpn-gui/vpn_dashboard_qt.py
Идея:
- показать mode = direct/smartdns/hybrid_wildcard;
- оставить старый toggle рабочим (маппинг direct/smartdns),
а hybrid можно добавить как отдельный выбор (позже).
--------------------------------------------------------------------
5) Порядок внедрения (рекомендуемый)
--------------------------------------------------------------------
Шаг 1:
Реализовать режимы + fallback + split-метрики (P1.1, P1.2, P1.3).
Шаг 2:
Добавить лимиты expansion (P1.4), проверить изменение unresolved/timeouts.
Шаг 3:
Добавить negative cache и PTR retry (P2.1, P2.2).
--------------------------------------------------------------------
6) Критерии готовности
--------------------------------------------------------------------
1. В trace видно не один dns_errors, а раздельные причины.
2. В режиме direct при падении одного upstream запросы частично продолжают проходить через fallback.
3. В режиме hybrid_wildcard wildcard-домены уходят через SmartDNS, остальные через direct.
4. Количество timeout и общее время прогона снижаются относительно текущего baseline.
--------------------------------------------------------------------
7) Короткий диагноз по сути
--------------------------------------------------------------------
Проблема не в одном SmartDNS bottleneck.
Основной вклад сейчас дает комбинация:
- большой domain expansion,
- много несуществующих имен (NXDOMAIN),
- и отсутствие четкой стратегии fallback/метрик.
Safe-путь:
ввести гибридный routing DNS + раздельную диагностику + контролируемый expansion.