-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
shadowsocks-reborn 5.x is a WinUI 3 desktop application split into platform-neutral core logic, Windows integration, WinUI integration, the product shell, and an isolated elevated capture helper.
Shadowsocks.WinUI
├── Shadowsocks.Core
├── Shadowsocks.Windows
└── Shadowsocks.Windows.WinUI
Shadowsocks.Windows
└── Shadowsocks.Core
Shadowsocks.Windows.WinUI
├── Shadowsocks.Core
└── Shadowsocks.Windows
Shadowsocks.NetworkService
└── isolated elevated process / named-pipe boundary
Projects:
-
Shadowsocks.Core(net10.0) — protocol, encryption, configuration model, PAC/GeoSite logic, localization, routing models, logging configuration and storage abstractions. -
Shadowsocks.Windows— file-storage bootstrap, WinINet/system proxy, startup, self-update, hotkeys, SIP003 package management/process hosting, UAC/Admin capture, WinDivert runtime and NetworkService coordination. -
Shadowsocks.Windows.WinUI— WinUI-specific Windows shell/tray integration. -
Shadowsocks.WinUI— unpackaged WinUI 3 application and product publish project. Release assembly name isShadowsocks. -
Shadowsocks.NetworkService— isolated elevated x64 helper that owns transparent WinDivert capture/routing. -
Shadowsocks.UnitTests— Core/Windows tests without presentation dependencies.
Shadowsocks.Core must remain free of WinUI, WinForms, WPF and Windows App SDK dependencies. Shadowsocks.NetworkService is deliberately not a normal executable ProjectReference of the product.
WinUI 3 is the only desktop presentation layer.
Startup flow:
Program.Main
↓
Windows App SDK AppInstance
↓ same-identity activation redirect
ProcessSingleInstanceGuard
↓ executable-identity-independent process gate
App
↓
WindowsStorageBootstrapper
↓
ShadowsocksController
↓
MainWindow / tray / pages
The application uses a stable AppInstance key for normal same-identity activation redirection and a separate named ProcessSingleInstanceGuard before controller startup. The second gate is intentionally independent of unpackaged WinUI executable identity, so the LocalAppData startup copy and an original/USB copy cannot both become controller owners. Same-identity user launches still redirect to the existing WinUI instance; a cross-identity duplicate exits before networking/controller startup.
Closing the main window hides it; the tray keeps the application alive. Explicit Quit performs controller shutdown and runtime cleanup.
Pages read state and perform operations through controller/services. They do not own a second networking/configuration model; persistence and Registry integration stay behind storage/Windows services except for simple shell actions such as opening the data folder.
WinUI-specific code belongs in Shadowsocks.WinUI or Shadowsocks.Windows.WinUI. Synchronous Windows integration belongs behind services in Shadowsocks.Windows; do not reintroduce WinForms/WPF to solve shell/platform tasks.
WinUI / tray
↓
ShadowsocksController
↓
GameModeManager / AdminCaptureManager
↓ named pipe
Shadowsocks.NetworkService (elevated)
↓
WinDivert
The Admin capture path opens a read-only WinDivert FLOW observer before the NETWORK packet handle. FLOW events populate endpoint-to-PID ownership used by routing; IP Helper tables remain a fallback for flows that pre-date the observer or are ambiguous. WinDivert 2.2.2 x64 runtime files are accepted only when their pinned SHA-256 values match. Fragmented datagrams that require transparent rewriting are dropped as a complete flow rather than allowing later fragments to bypass the first-fragment decision.
Only User and Admin are selectable traffic modes.
- User Mode does not require elevation or NetworkService extraction.
- Admin Mode acquires an on-demand NetworkService runtime lease, launches the broker elevated, validates its protocol version, and enables transparent TCP/UDP capture.
- Game Mode is automatic: a configured running application suspends Admin capture while keeping Admin as the configured mode. Capture restores automatically when the trigger exits.
Application rules support Proxy, Direct and Block.
Core uses ISettingsStore; product startup configures JsonFileSettingsStore.
Normal mode:
%LOCALAPPDATA%\Shadowsocks
settings.json
settings.backup.json
Cache\...
Data\...
Plugins\...
Logs\...
Runtime\...
Clean Mode is selected by an executable stem ending in p and redirects the same logical tree to:
%TEMP%\Shadowsocks\Clean\<session>\...
The Registry is not an application-configuration backend. Registry access remains only for Windows integrations that require it (Run, protocol association, WinINet/system proxy, discovery reads).
The release directory is immutable application code. Product runtime does not use executable-side files as a configuration, migration, plugin, cache, log or update source.
See STORAGE_POLICY.md.
Default application resources are embedded. Mutable state is externalized:
- PAC/user data →
%LOCALAPPDATA%\Shadowsocks\Data\PAC; - Online PAC cache →
%LOCALAPPDATA%\Shadowsocks\Cache\PAC; - GeoSite cache/runtime →
%LOCALAPPDATA%\Shadowsocks\Cache\GeoSiteandRuntime\WinDivertas applicable; - SIP003 plugin packages →
%LOCALAPPDATA%\Shadowsocks\Plugins(or the active Clean Mode storage root); - localization → embedded
Shadowsocks.Core.Data.i18n.csvonly; - logs →
%LOCALAPPDATA%\Shadowsocks\Logs.
NLog is configured programmatically; product deployment does not require NLog.config.
When Start with Windows is enabled, AutoStartup copies the current executable to:
%LOCALAPPDATA%\Shadowsocks\Startup\Shadowsocks.exe
The copy is SHA-256 checked and the HKCU Run entry points to that stable path with --start-hidden. A legacy-only matching Run entry is migrated to the canonical entry; stale matching values are removed both while autostart is enabled and when it is disabled. A process-wide named gate also prevents concurrent startup-copy/original-EXE controller startup. Start with Windows is disabled in Clean Mode.
Application updates use the canonical GitHub assets Shadowsocks-win-x64.zip and Shadowsocks-win-x64.zip.sha256. The updater rejects missing/non-canonical assets, invalid GitHub release URLs, checksum mismatches, ZIPs that do not contain exactly one root Shadowsocks.exe, and payloads whose file version does not match the selected release.
The single-file handoff is:
- download and verify the release into
%TEMP%\Shadowsocks\Updates\<transaction>; - extract the new payload as
Shadowsocks.Update.exe, calculate its SHA-256 and retain a read-only/non-deletable handle across process creation/UAC; - start that payload with the internal
--updatehandoff plus the expected updater digest, and only then shut down the current instance; - the temporary payload re-verifies its own staged image against the handoff digest before replacement, waits for the old PID, keeps a rollback copy, replaces the product EXE and starts the installed new copy;
- the installed new copy waits for the temporary updater to exit and removes the transaction/rollback files.
If the running process is the stable Start-with-Windows copy, its Run command carries the original product EXE path via an internal startup-origin argument so updates replace the user-facing product binary rather than only the LocalAppData startup copy. Clean Mode executables are updated under their current ...p.exe name while the self-update transaction itself stays outside the disposable Clean Mode session. Release packaging additionally verifies that the published Shadowsocks.exe FileVersion exactly matches the requested release version before ZIP creation.
Product publish uses a separate build step for the elevated helper:
- publish
Shadowsocks.NetworkServiceas self-contained, win-x64 and single-file; - embed the helper EXE as
Shadowsocks.WinUI.Embedded.Shadowsocks.NetworkService.exe; - bundle that resource into the final
Shadowsocks.exe; - reject every release sidecar.
Admin runtime materialization:
- hash embedded helper bytes;
- serialize extraction with a named mutex;
- create a unique
Temp\NetworkService\<version>\<hash>\<pid-guid>directory below the active storage root; - write and verify the helper SHA-256;
- launch with UAC;
- verify helper version over the control-pipe
pinghandshake; - keep a guard handle for the broker lifetime;
- remove the current run directory on shutdown and prune stale directories later.
User Mode does not extract NetworkService.
Release profile:
unpackaged
self-contained
win-x64
PublishSingleFile
WindowsAppSDKSelfContained
Distribution invariant:
Release/
└── Shadowsocks.exe
CI, packaging/Build-Release.ps1 and packaging/Validate-Repository.ps1 enforce the project boundaries and one-file release layout.