zapret-kvn/docs/UI_AND_OFFLINE_GEOIP.md
loop-uh 4d82c490cf
Some checks failed
Windows project source guards / test (push) Failing after 50s
fix: retain authenticated AWG while checking HTTPS in background
2026-09-06 15:36:10 +03:00

17 KiB
Raw Permalink Blame History

Главная, серверы и локальная GeoIP

Главная использует стандартные карточки qfluentwidgets и прозрачные поверхности для Mica. Подробные графики и процессы доступны на внутренних страницах. Нормальный размер окна сохраняется; восстановление выполняется при загрузке состояния, а не при каждом изменении настроек. Базовый минимум — 860×560, первый размер — 1000×720 логических пикселей с ограничением по рабочей области.

Серверы показаны через одну Fluent TableView с плоской моделью и строками 28 px. По умолчанию они сгруппированы по ID подписки; одноимённые подписки не смешиваются. Группировку можно отключить либо переключить на поле группы, страну или протокол. Столбец имени больше не растягивается вслед за окном. Меню «Вид» управляет столбцами и группами; избранное доступно через контекстное меню и меню «Ещё». Поиск скрыт до Ctrl+F. Мышь, множественное выделение, двойной щелчок, копирование ссылок, контекстное меню и клавиатурная навигация остаются доступны. Тонкие границы строк и колонок рисуются только в видимой области, без создания виджета для каждого сервера.

Флаги и состояние активности обновляют только соответствующие ячейки. Пакеты метрик пересортировывают список только при изменении текущего ключа сортировки. Обновления метрик свёрнутых групп не отправляют уведомления представлению; их пересортировка откладывается до раскрытия. Данные и выделение сохраняются. Сортировка сохраняет постоянные индексы; при изменении состава списка выделение восстанавливается по ID оставшихся серверов, а свёрнутые группы — по ключам.

Данные и совместимость

  • Node.is_favorite и Node.country_override сохраняются вместе с профилем. Обновление подписки переносит эти поля через существующее сопоставление узлов.
  • country_code — вычисляемое поле в памяти. Старые сохранённые предположения о стране при загрузке игнорируются.
  • Настройки вида имеют nodes_column_layout_version = 2, поля nodes_group_by, nodes_favorites_only, nodes_collapsed_groups и сохраняемые ширины всех столбцов. Индивидуальная видимость столбцов сохраняется при миграции.

Сетевой контракт GeoIP

Ручной выбор страны имеет приоритет. Если в имени есть флаг-эмодзи, используется его код страны; эмодзи убирается только из отображаемого имени и заменяется PNG. Оригинальное имя и ссылка сохраняются. Обычные слова и буквенные коды в имени не используются для угадывания страны.

Для серверов без флага используется локальная DB-IP Country Lite MMDB. Оно никогда не вызывает DNS, DoH/DoT, HTTP, внешние GeoIP API, тестовые подключения или запросы внешнего IP. Домены без уже известного IP остаются без страны. Результаты штатного разрешения endpoint передаются пассивно; геолокация не инициирует разрешение и не меняет routing/DNS конфигурацию ядра.

Для AWG/WireGuard используются peer endpoint, а не адрес интерфейса или AllowedIPs. Разные страны у неоднозначных endpoint означают отсутствие автоматического результата. Ручная страна имеет приоритет. Флаги загружаются только из настоящих PNG; неизвестный код или недостающий файл не подменяются полосами либо другой картинкой.

Сборочная база

release_windows.py перед фиксацией исходников нового stable запускает prepare_geoip.py --refresh. Скрипт получает последний доступный ежемесячный снимок с официальной страницы DB-IP, проверяет MMDB и записывает дату и хеши в scripts/geoip-lock.json. Бинарные данные остаются в .cache/geoip.

build.py включает закреплённые данные в assets/geoip вместе с атрибуцией. Dev/stable gates проверяют хеш в итоговом payload. Возобновление релиза не выбирает новую базу; несовпадение хеша или недоступность источника при подготовке нового stable останавливают соответствующий этап. В приложении нет загрузчика или кнопки обновления GeoIP.

Источник и лицензия: DB-IP Country Lite, CC BY 4.0.

Запуск и проверки

Splash удалён. StartupLoader читает состояние в рабочем потоке и передаёт ранние параметры темы и геометрии до показа окна. Виджеты и Qt-модели остаются в GUI-потоке. Неоткрытые страницы получают последние снимки через DeferredPage и создаются при первом обращении. Версии ядер и пресеты подготавливаются отдельно; геолокация не задерживает подключение.

Отмена до загрузки состояния не сохраняет пустое состояние поверх реального. Логи запуска содержат длительность подготовки и готовности управления. Проверки включают 10 000 узлов, устойчивость выбора и ширин, запрет сетевых вызовов из GeoIP, отмену загрузки и проверку сборочных хешей. Проверка Mica и фактического времени запуска Windows EXE выполняется после ручной сборки.

DNS и первое подключение

Штатные JSON-шаблоны sing-box используют native fallback: DoH через VPN → прямой DoH с устройства → системный DNS. Внутри каждого DoH-этапа три резолвера проверяются параллельно с ограниченным временем ожидания. IP адреса DoH заданы явно, сертификаты проверяются по TLS server_name. NXDOMAIN считается ответом, а не причиной обходить настроенный resolver.

Переход на резерв отмечается WARN в логе ядра и предупреждением интерфейса. Для системного DNS отдельно указано, что запросы могут быть видны провайдеру. Последовательность принадлежит native JSON. Секция dns автоматически перезаписывается из текущего стандартного шаблона при запуске, чтении и сохранении активного конфига, включая изменённые пользователем копии. Остальные поля (маршрутизация, outbounds, параметры интерфейса) сохраняются. Запись атомарная; неизменившаяся DNS-секция не вызывает повторную запись на диск. Для движка без DNS-секции в штатном шаблоне новая политика не придумывается.

Amnezia запускает одну ограниченную волну HTTPS-проб, которая инициирует handshake. Подтверждение авторизации берётся из статистики собственного ядра. После handshake уже запущенные пробы завершаются в фоне; без handshake запуск по-прежнему завершается ошибкой. Отмена подключения отменяет наблюдение за пробами.

Hysteria использует тот же общий SOCKS/HTTPS probe, что и Amnezia. До старта sing-box DNS пробы используют IP с исходным TLS SNI и проверкой сертификата. Официальное событие INFO connected to server подтверждает завершённую авторизацию Hysteria. После него запуск продолжается, а уже запущенная волна HTTPS-проб завершается в фоне без новых сетевых запросов. Отказ всех проверочных адресов вызывает одно предупреждение и запись в журнале, но не отключает подтверждённое соединение. Успешная авторизация сама по себе не доказывает доступность произвольных сайтов — это различие явно видно в предупреждении.

Без подтверждения авторизации и без успешной HTTPS-пробы запуск по-прежнему завершается ошибкой. Ошибки сертификата и авторизации обрабатываются сразу. Остановка или замена процесса отменяет наблюдение за старыми пробами; их результаты не меняют статус новой сессии. Диагностика отдельно сохраняет remote_authenticated и https_check в статистике Hysteria.

Штатный QUIC режим соответствует Android: ChromeParrot выключен, параметры obfs и TLS pin из профиля сохраняются. Информационные сообщения официального клиента попадают в журнал с удалёнными секретами. Структурированные события разбираются до удаления секретов, но после удаления цветовых кодов терминала.

Регрессия проверяется настоящим локальным ядром Hysteria: сервер принимает авторизацию, а тестовый TCP-адрес молча удерживает TLS ClientHello. Windows release gates используют поставляемое ядро; на Linux тест включается через HYSTERIA_TEST_BINARY. Все адреса интеграционного теста находятся на loopback.

AWG: DNS после подтверждённого транспорта

Первый этап AWG требует подтверждённый handshake. HTTPS по IP проверяется в фоне и не отключает туннель при отказе фиксированных проверочных адресов. Проверка доменных адресов после запуска sing-box ставится в очередь за IP-пробами и выполняется в фоне общим BackgroundHealthCheck, который также используется Hysteria. Отказ DNS/HTTPS по доменам записывает одно предупреждение и front_dns_check=warning, сохраняя авторизованный туннель. Handshake сам по себе не доказывает работоспособность прикладного трафика; предупреждение и поля https_check / front_dns_check сохраняют это различие. Ошибка отдельного сайта не переводит весь VPN в состояние ошибки. Сбой процесса, наблюдателя и исчерпание handshake остаются фатальными; результаты отменённой сессии не влияют на следующую.

Делегирование DNS в sing-box ждёт до 15 секунд вместо 5, чтобы native fallback успевал перейти к резерву. SOCKS CONNECT имеет отдельный бюджет 30 секунд после авторизации, включающий DNS и TCP; завершение сессии по-прежнему отменяет запросы. Отдельный resolver в AWG не добавляется. Локальный тест с DNS-ответом через 5,2 секунды воспроизводит отказ прежней версии и проходит после исправления.

Кэш таблицы в памяти

NodesGroupModel хранит до 8192 значений ролей запрошенных ячеек в ОЗУ. Повторное открытие вкладки и resize используют этот же кэш, пока данные не изменились. Изменение узла инвалидирует его строку, включая скрытые строки; изменения структуры, сортировки или темы очищают соответствующий кэш. Дисковый кэш не создаётся. Скрытые группы не получают отрисовку или пересортировку из-за фонового пинга.

Плоские рамки рисуются тонкими прямоугольными полосами, без дорогой растеризации скругления каждой широкой строки. Пересчёт ширин после resize объединяется в один вызов на 16 мс; изменение только высоты не перераспределяет колонки, неизменившиеся секции повторно не изменяются. Выбор, мультивыбор, раскрытие групп, сортировка и контекстные действия продолжают использовать живую Qt-модель.

На локальном offscreen-стенде с 884 узлами и областью 1720×900 профиль 20 кадров сократился примерно с 0,69 до 0,30 с. Это замер изолированной таблицы на Linux, а не измерение Windows Mica или пользовательского компьютера.

Проверка Android

В Android 447328b проверен путь VpnHealthPipeline → ZapretVpnService. Он проверяет DNS и три HTTPS-адреса через VPN, затем делает одну спасательную попытку; отказ всех проб закрывает сессию. Это отдельный строгий gate, который нельзя считать исправленным Windows-изменением. JVM-проверки: 336 тестов без ошибок. ADB-устройств и туннеля 15037 при проверке не было; испытание на телефоне и изменение Android VPN/DNS без диагностик устройства не выполнялись.