177 lines
17 KiB
Markdown
177 lines
17 KiB
Markdown
# Главная, серверы и локальная 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](https://db-ip.com/db/download/ip-to-country-lite),
|
||
[CC BY 4.0](https://creativecommons.org/licenses/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 без диагностик устройства не выполнялись.
|