17 KiB
Главная, серверы и локальная 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 без диагностик устройства не выполнялись.