Skip to content

RU Architecture

SlimRG edited this page Aug 23, 2026 · 1 revision

Архитектура

shadowsocks-reborn 5.2.31 — настольное WinUI 3-приложение под Windows 10/11 x64. Код разделён на нейтральное ядро, Windows-интеграцию, WinUI-интеграцию, основной UI и изолированный повышенный helper для прозрачного перехвата.

Граф проектов

Shadowsocks.WinUI
  ├── Shadowsocks.Core
  ├── Shadowsocks.Windows
  └── Shadowsocks.Windows.WinUI

Shadowsocks.Windows
  └── Shadowsocks.Core

Shadowsocks.Windows.WinUI
  └── самостоятельная WinUI-библиотека интеграции shell/tray

Shadowsocks.NetworkService
  └── отдельный elevated-процесс
      + linked-копия dependency-free FilterEngine.cs
  • Shadowsocks.Core (net10.0) — конфигурация, протокол, шифрование, GeoSite, PAC-модель, managed routing, локализация и общие сервисы.
  • Shadowsocks.Windows — системный proxy, storage bootstrap, startup, self-update, hotkeys, плагины, UAC/Admin Mode, WinDivert и координация NetworkService.
  • Shadowsocks.Windows.WinUI — WinUI-specific tray/QR/power/shell integration; проект намеренно не тянет Core/Windows через ProjectReference.
  • Shadowsocks.WinUI — основной unpackaged WinUI 3 shell. Release assembly: Shadowsocks.
  • Shadowsocks.NetworkService — x64 helper с повышенными правами для transparent TCP/UDP capture.
  • Shadowsocks.UnitTests — unit/integration tests без presentation-зависимостей.

Shadowsocks.Core не должен зависеть от WinUI, WinForms, WPF или Windows App SDK. WinForms/WPF в проект не возвращаются.

Managed routing: окончательный Variant B

Local GeoSite + EasyList/ABP работает только через C# Shadowsocks.Routing.FilterEngine.

GeoSite + user-rule.txt
        ↓
C# FilterEngine
        ↓
RoutingDecision
   ├── DIRECT
   └── PROXY

Исторические abp.js, compiled-PAC backend, переключатель backend и исполняемый abp.txt удалены. user-rule.txt — поддерживаемый пользовательский набор локальных правил.

Поддерживаемый network-filter subset включает @@, ||domain^, | anchors, *, ^, regexp-правила, $domain= и $match-case. Простые domain anchors индексируются по suffix; сложные правила проходят через keyword index и bounded decision cache.

User Mode / Local PAC

Windows всё равно требует PAC как механизм настройки системного proxy, поэтому Local PAC содержит только минимальный FindProxyForURL, который отправляет запрос в локальный managed proxy. Сам PAC не принимает решение DIRECT/PROXY.

WinINet / system PAC
      ↓
минимальный PAC funnel
      ↓
ManagedHttpProxyService
      ↓
application rules
      ↓
C# FilterEngine
      ↓
DIRECT / PROXY

Online PAC

Online PAC — отдельный явно включаемый режим. Внешний .pac является JavaScript-программой по стандарту PAC и исполняется Windows. Это не часть Local EasyList/ABP engine и не возвращает abp.js.

Administrator Mode

На SYN-этапе WinDivert знает PID и destination IP, но обычно не знает hostname. Поэтому обычный TCP без явного application rule сначала получает Deferred.

Transparent TCP relay буферизует только ограниченный начальный фрагмент (до 64 KiB) и ищет:

  • HTTP request line + Host;
  • TLS ClientHello SNI.

TLS не расшифровывается, CA не устанавливается, сертификаты не подменяются. После Host/SNI helper запускает тот же dependency-free FilterEngine и выбирает direct socket либо существующий Shadowsocks SOCKS5 path.

Application Direct / Proxy / Block rules имеют приоритет. UDP не содержит надёжного hostname на этом уровне; ECH/no-SNI/server-first и неизвестные протоколы используют детерминированный fallback. DNS/53 обрабатывается отдельной DNS policy.

DNS

DNS policy поддерживает System, Direct, Proxy, CustomDoh и DnsCrypt.

В Administrator Mode UDP/TCP 53 перехватывается прозрачно. DNSCrypt runtime запускается как управляемый внешний компонент, скачиваемый по требованию. Активный DNSCrypt работает fail-closed: plaintext fallback во время переходов/сбоев не допускается.

Жизненный цикл приложения

Program.Main
  ↓
Windows App SDK AppInstance
  ↓
ProcessSingleInstanceGuard
  ↓
App
  ↓
WindowsStorageBootstrapper
  ↓
ShadowsocksController
  ↓
MainWindow / tray / pages

Закрытие окна скрывает его; приложение продолжает работать в tray до явного Quit. Одновременно используется AppInstance redirect и отдельный process-wide guard, поэтому оригинальный EXE и LocalAppData startup-copy не могут одновременно владеть controller/ports.

Плагины

SIP003-плагины устанавливаются в управляемое хранилище Plugins\<plugin-id>. Built-in catalog: xray-plugin, v2ray-plugin, qtun. Только этот доверенный каталог допускается к фоновому сетевому обновлению: controller запускает maintenance после старта, менеджер ограничивает успешные release-checks интервалом 24 часа, а используемый plugin откладывает до следующего прохода. Ручной ZIP/TAR.GZ import никогда не auto-update. Обновление проходит через staging + rollback-safe directory swap с повторной проверкой provenance перед заменой. Произвольный repository source не принимается до отдельного trust/asset-selection контракта. Runtime не должен молча искать executable через PATH или рядом с Shadowsocks.exe.

Обновление

Self-update использует канонический Shadowsocks-win-x64.zip и .sha256, проверяет checksum, структуру ZIP и FileVersion, staging выполняет в %TEMP%\Shadowsocks\Updates. Замена rollback-safe и отвергает equal-version/downgrade payload.

Storage

Mutable state никогда не записывается рядом с release EXE. Подробности: Политика хранения.

Связанные страницы

Bootstrap resolver-каталога DNSCrypt

Shadowsocks Reborn самостоятельно обновляет подписанный каталог DNSCrypt, не позволяя dnscrypt-proxy разрешать hostnames удалённых sources через bootstrap DNS. Основной resolver — Cloudflare DoH (1.1.1.1, TLS/SNI cloudflare-dns.com), резервный — Google DoH (8.8.8.8, TLS/SNI dns.google); оба HTTPS-соединения DoH открываются через активный локальный SOCKS5 Shadowsocks. После разрешения имени источника загрузка public-resolvers.md и .minisig также идёт через Shadowsocks.

Размер загрузок ограничен, а пара проверяется закреплённым публичным Minisign-ключом DNSCrypt до публикации. Затем dnscrypt-proxy получает только локальный аутентифицированный кэш с urls = [], bootstrap_resolvers = [] и ignore_system_dns = true. Если обновление временно недоступно, может использоваться уже существующий валидный подписанный кэш; при отсутствии валидного кэша операция завершается fail-closed, а предыдущий DNS mode сохраняется.

Clone this wiki locally