Files
Vole/example/windows-uwp
yiguodev 608a8f255c feat: add client protocols, TLS capabilities, and platform validation (#1)
* chore: download latest official mihomo for interop tests

* test: capture N0 baseline and protocol feasibility probes

* docs: record N0 hybrid REALITY fork verification

* test: verify N0 controlled Hysteria2 auth and streams

Add an isolated Quinn adapter over existing DIRECT and SOCKS5 datagrams, bounded queues, protect rejection probes, and official latest peer fixtures. Record passing auth/TCP checks and the native Hysteria half-close failure separately. N0 remains incomplete; production sources and dependency locks are unchanged.

* test: validate N0 native QUIC hopping and XHTTP H3

Keep the probes isolated from production. Verify one-state Hysteria hopping, protected rebind rejection, Xray H3 entry and existing HY2 regressions. Set only the owned Linux peer MTU to avoid Initial-packet EMSGSIZE; retain native half-close failures as separate gates.

* fix: align XHTTP shutdown with Mihomo connection close

* test: verify N0 supplied-stream transport interfaces

Add isolated TLS, ordinary WebSocket and gRPC probes with owned I/O, bounded buffers and cancellation barriers.

Match Mihomo close behavior: preserve TLS/WS reads, distinguish clean WS underlay EOF from truncation, and close both gRPC directions. Use separate official SOCKS5 peers to avoid fixture loop detection.

Record 12 Debug/Release tests, 42 official Mihomo checks, dependency audits and Apple/Android compile checks. Keep production dependencies, third-party sources and remaining N0 gates unchanged.

* fix: upgrade h2 and retain completed responses after reset

* chore: use the current OneXray rustls fork origin

* chore: adopt published rustls 0.23.45 and official TLS binding

* chore: refresh N1 foundation and spike dependencies

* feat: validate next-protocol field and combination catalogs

* feat: share immutable TLS policies and bounded close semantics

* feat: add shared stream transports and decouple XUDP framing

* feat: add controlled datagram foundations and N1 acceptance harness

* chore: finalize N1 with verified x25519 dependency

* chore: publish N1 against the rustls release branch

* feat: add bounded Trojan request and datagram codecs

* feat: connect Trojan TLS TCP and UDP through the runtime

* feat: support Trojan WebSocket and duplex gRPC transports

* feat: enable Trojan and complete N2 consumer acceptance

* feat(vmess): add bounded AEAD header and body codecs

* fix(vmess): align close acceptance with Mihomo transports

* feat(vmess): add UDP codecs and isolated peer comparisons

* feat(vmess): complete public runtime and N3 acceptance

* docs: bind N3 acceptance and refresh validation guidance

* feat(vless): complete N4 transports, Vision and UDP support

Extract VLESS assembly, add plain/TLS stream transports, HTTPUpgrade, node-owned gRPC pooling, mTLS and classic REALITY, and implement Vision through public TLS record boundaries. Preserve XHTTP and the XUDP default while adding raw and packetaddr.

Complete 145 required groups and 39 field rows against isolated latest official peers, with 160 lifecycle/resource rounds, independent coverage and Apple/Android release builds. Preserve the three explicit WS/REALITY layered close comparisons and historical failures in the acceptance report. No third-party or dependency-lock changes.

* feat(vless): complete N5 XHTTP and sing-mux support

Add H1/H2/H3 request fields, independent download security and pools, bounded packet-up batching, and h2mux/smux/yamux over controlled transports.

Keep Mihomo-aligned close and path semantics, node-owned shutdown barriers, and isolated official-peer fixtures including the approved Caddy mTLS gateway.

Validate 416 required groups, 57 fields, 112 two-leg security checks, 240 lifecycle/resource cycles, independent coverage, and Apple/Android release builds. Record native-peer gaps and leave N6-N10, devices, CI, and release gates separate.

* feat: integrate boring TLS profiles and retire rustls fork

* test(tls): freeze selected fingerprint reference baseline

* docs(tls): record selected-profile library acceptance

* feat(tls): integrate selected client fingerprints and REALITY profiles

* feat(tls): complete selected fingerprint CF5 acceptance

* feat(hysteria2): complete N6 client support and acceptance

Implement Hysteria2 over official Quinn/h3/rustls and shared controlled IO, including TCP/UDP, bandwidth pacing, Salamander, port hopping, upstream snapshots and synchronous Stop.

Keep old-path receives active for the full bounded handover window, preserve independent reader wakeups, and require the exact nested TCP evidence assertions.

Validate one frozen N6 run: 36 required groups, 20 field rows, native Mihomo/Hysteria peers, H3 regression, 40 lifecycle rounds and Apple/Android production builds. Record independent coverage, artifact hashes and native-peer limitations.

* test(tls): record N7 hybrid REALITY prerequisite evidence

Preserve the locked classic-only API failure and distinguish the locally accepted boring hybrid extension from pending VCore S03/D16 integration. Record wrapper feasibility and publication boundaries without changing production configuration or dependencies.

* feat(vless): support explicitly required hybrid REALITY

* feat(crypto): wrap official BLAKE3 binary-context derivation

* feat(vless): implement authenticated Encryption wire transport

* feat(vless): enable authenticated Encryption across public transports

* build(tls): pin the authenticated ShadowTLS ClientHello hook

* feat(vless): add authenticated JLS transport security

Pin the separately approved boring JLS revision and expose strict main/download credentials under schema 24. Preserve native CertificateVerify and Finished, cancellation, and controlled IO ownership. Accept the JLS field slice with 122 isolated cases, 80 lifecycle/resource cycles, and Apple/Android release libraries; keep broader N7 gates separate.

* docs(n7): reconcile current JLS acceptance progress

* chore(vless): retire Restls while retaining JLS

* feat(vless): complete N7 static ECH and security combinations

Add static ECH for VLESS main and XHTTP download legs using existing TLS backends and official Rust HPKE. Keep Invoke v5 and advance the internal schema to revision 27.

Accept the narrowed N7 scope with 43 required groups, 11 fields, 301 isolated native cases, 240 lifecycle/resource rounds, and Apple/Android release builds. Record frozen inputs, 470 container cleanups, explicit upstream comparison gaps, and prior failed runs in docs/acceptance/next-protocols/N7.md.

* chore(protocols): retire WireGuard scope and foundations

* test: complete N9 protocol integration and resource gates

* build: add N10 production artifact evidence gates

* fix: restore Windows snapshot encoding and fail-closed delivery CI

* fix: use native ARM64 LLVM assembly and scoped delivery CI

* build: keep delivery lockfile bytes stable across platforms

* fix: preserve production guard lifecycle and isolate CI feature checks

* build: adopt released boring and registry shadowsocks

* ci: use release-oriented workflow names

* docs: consolidate contracts and streamline test tooling

Merge current protocol and platform contracts, remove milestone reports and obsolete spikes, and share core checks between local development and CI. Preserve all 884 executable case definitions and unique legacy assertions.

Validation: core Debug/Release, feature checks, Clippy, netstack, offline script tests, formatting and documentation links passed locally. Container interop smoke attempts failed during official peer downloads; business paths remain NOT RUN.

* test: replace milestone names with capability-based validation

Rename protocol and fingerprint suites, fixtures, and evidence identifiers by capability. Preserve acceptance cases and golden wire data while documenting reference, wire, and interoperability evidence separately.

* fix: address review findings and stabilize core CI

Flush accepted gRPC/H2 data through the supplied IO before reset, and wait for pending smux writes before FIN. Sanitize AnyTLS peer failures, reject XHTTP userinfo, and remove stale Android delivery artifacts.

Close container log capture even when inventory fails. Keep legacy host suites blocked before resource acquisition.

Separate Shadowsocks adapter codec checks from upstream strict server acceptance. Lock the random empty-request zero-padding failure with deterministic negative and positive fixtures, without changing the dependency or production behavior.

* test: isolate delivery fixture from Windows home lookup

* test: preserve UDP socket semantics during peer teardown

The memory peer treated its counterpart closing an mpsc channel as a local UDP BrokenPipe. That could terminate Quinn endpoint IO without waking a pending wait_idle, despite all four datagrams and CONNECTION_CLOSE having arrived.

Keep a closed peer link silent and late sends best-effort, add a deterministic fixture regression, and preserve the existing data and shutdown deadlines. Debug/Release, Clippy, and 300 consecutive regression iterations pass.

* fix: drain XHTTP uploads before releasing connection drivers

* fix: enforce lazy setup deadlines and safe delivery paths

Check the original deadline before accepting ready gRPC/H2 headers or sing-mux status, without limiting established reads. Reject symlinks and Windows reparse points in every delivery output path before filesystem mutations. Add deterministic memory and temporary-filesystem regressions.

* test: join XHTTP H3 peer tasks during cleanup

Quinn retains closed connections for three probe timeouts, so a delayed handshake can legitimately exceed the fixture's two-second wait_idle budget. Own, abort, and join the passive peer tasks after upload and client shutdown instead. Preserve upload integrity and client close bounds, and cover delayed handshakes in both streaming modes.
2026-09-28 12:50:01 +08:00
..
2026-09-22 11:15:24 +08:00
2026-09-22 11:15:24 +08:00
2026-09-22 11:15:24 +08:00
2026-09-22 11:15:24 +08:00

VCore Windows UWP VPN 最小集成

本示例演示如何把 VCore 的 Windows.Networking.Vpn Provider、每会话完全信任运行时和一个最小命令行前台打进同一个 MSIX,并通过 VCoreWindowsVpnInvoke 创建、连接、查询和停止系统 VPN。

这里的 “UWP” 指 Windows 的 UWP VPN Provider 模型。VCore 不支持纯 AppContainer 前台直接承载完整集成:profile/snapshot 管理必须由同包的完全信任进程执行,Session Host 则由 Provider 激活。已有纯 UWP UI 时,应增加一个完全信任 broker;不要从 UWP UI 直接调用桥接接口。

最小架构

VCoreUwpDemo.exe(完全信任前台)
  └─ VCoreWindowsVpnInvoke
       ├─ 发布不可变配置快照
       ├─ 创建/更新同包 VPN profile
       └─ ConnectProfileAsync

vcore-windows-vpn-host.exe + vcore.dll(AppContainer Provider)
  ├─ VpnChannel / routes / DNS assignment / packet buffers / physical network
  └─ FullTrustProcessLauncher
       └─ vcore-windows-session-host.exe(每次连接一个完全信任进程)
            └─ 完整 VCore:netstack / DNS / rules / outbounds

前台退出不会停止 VPN。Provider 或 Session Host 退出、管道损坏、非法 frame 或物理网络变化会失败关闭当前 VPN。

文件

文件 用途
demo.cpp 最小完全信任宿主;读取 YAML,调用 revision-3 Windows bridge
demo.yaml 无真实凭据的生命周期示例;把流量交给 127.0.0.1:1080 SOCKS5
AppxManifest.xml.in 完整最小 MSIX manifest,包括 Provider、Session Host 和受限能力
build.ps1 构建三项 VCore 产物、编译 demo、打包、签名并可选安装

示例没有实现第二套 Provider、netstack、管道协议或 profile 管理代码;这些都由 VCore 现有产物提供。

前置条件

  • Windows 10 20H2 build 19042 或更新版本;
  • uv、Visual Studio C++ 工具和 Windows 10/11 SDK;
  • 与当前处理器对应的 Rust Windows MSVC target:aarch64-pc-windows-msvc 或 x86_64-pc-windows-msvc;
  • 可用于目标 Publisher 的代码签名证书,并已由测试设备信任;
  • 旁加载需要开发者模式或组织允许的安装策略;
  • Store 发布需要正式 package identity、publisher、networkingVpnProvider 与 runFullTrust 审批。

构建脚本要求显式传入 -PfxPath、-PfxPassword 和与证书 Subject 一致的 -Publisher。脚本只读取证书并签名,不生成、导入或删除证书。

构建与安装

在仓库根目录执行:

powershell -ExecutionPolicy Bypass -File example/windows-uwp/build.ps1 `
  -Version 1.0.0.0 `
  -PfxPath C:\path\to\development.pfx `
  -PfxPassword '<password>' `
  -Publisher 'CN=Development Publisher' `
  -Install

脚本从 Windows 系统注册表自动选择原生 ARM64 或 x64 架构,不接受架构参数。默认通过 uv run --project scripts --locked vcore-scripts build windows 构建 VCore;已经生成当前架构产物时可以加 -SkipVCoreBuild。输出位于:

dist/windows-uwp-demo/VCore.UwpDemo.Dev_<version>_<arch>.msix

更新已安装包前必须先停止 VPN,并把四段式 MSIX 版本提高。架构必须在 demo、vcore.dll、Provider Host、Session Host 和 manifest 中保持一致。

运行最小 demo

安装后重新打开终端,让 App Execution Alias 生效:

vcore-uwp-demo.exe environment
vcore-uwp-demo.exe status

$config = (Resolve-Path example/windows-uwp/demo.yaml).Path
vcore-uwp-demo.exe start $config
vcore-uwp-demo.exe status
vcore-uwp-demo.exe stop

典型响应:

{"success":true,"data":{"status":"disconnected","snapshotToken":null},"error":""}

start 成功时返回 connected 和内容寻址的 snapshotToken。不要解析错误文本判断状态;使用 success 和 data.status。

demo.yaml 只用于 lifecycle smoke:

  • 它不包含真实凭据;
  • 它假设外部 SOCKS5 服务监听 127.0.0.1:1080 并支持 UDP;
  • 未启动 SOCKS5 时 VPN 仍可进入 Connected,但业务流量会按流失败;
  • dns.enable: false 表示 TCP/UDP 53 保留原目标并作为普通流量走 SOCKS5;
  • 外部 SOCKS5 服务自行负责其外层 socket 的 VPN 绕过和进程生命周期。

要验证真实流量,请把命令中的 YAML 换成自己的合法 VCore TUN 配置,或先启动符合上述约束的外部 SOCKS5 服务。不要把真实配置、secret 或响应前的完整请求写入日志。

前台调用契约

demo.cpp 直接链接构建产物的 vcore.dll.lib,运行时从同目录加载 vcore.dll:

#include "vcore.h"

char* response = VCoreWindowsVpnInvoke(request_json);
if (response != nullptr) {
    // 读取 UTF-8 JSON;不要使用 host allocator 释放。
    VCoreFree(response);
}

约束:

  • 请求是 NUL 结尾 UTF-8 JSON,最大 1 MiB;
  • revision 固定为 bridgeVersion: 3;
  • DTO 严格拒绝未知字段;
  • 返回内存必须由同一份 vcore.dll 的 VCoreFree 释放;
  • 桥接命令不能重叠;真实前台应在单进程内串行调用,本命令行 demo 额外用 session-local named mutex 串行化多个 alias 进程;
  • 调用进程必须具有当前 MSIX package identity;unpackaged EXE 会失败关闭;
  • 不要从 Provider 回调、Session Host 或 AppContainer UI 重入该接口。

最小宿主只使用四个方法:

方法 payload 用途
getEnvironment {} 验证 package identity,返回 PFN 和 LocalState 路径
getVpnStatus {} 查询同包唯一 profile
startVpn configYaml + networkSettings + policy + 可选 sessionBackend 发布 Session Snapshot、配置全局 VPN policy 并连接
stopVpn {} 断开当前 profile

桥接还提供 getStartupTaskStatus 和 setStartupTaskEnabled。本 demo 故意不声明 StartupTask,避免登录时启动一个无 UI 的命令行工具;产品需要该能力时,再声明 xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"、把 desktop 加入 IgnorableNamespaces,并在前台 <Application> 下增加:

<desktop:Extension Category="windows.startupTask"
                   Executable="YourHost.exe"
                   EntryPoint="Windows.FullTrustApplication">
  <desktop:StartupTask TaskId="VCoreStartup"
                       Enabled="false"
                       DisplayName="Your App" />
</desktop:Extension>

startVpn 请求

最小请求形状:

{
  "bridgeVersion": 3,
  "method": "startVpn",
  "payload": {
    "configYaml": "tun:\n  enable: true\n...",
    "networkSettings": {
      "ipv4Address": "192.168.3.1",
      "ipv6Address": "fd00::2",
      "dnsIpv4Address": "223.5.5.5",
      "dnsIpv6Address": "2400:3200::1"
    },
    "policy": {
      "alwaysOn": false,
      "allowLocalNetwork": true,
      "excludedCidrs": []
    }
  }
}

networkSettings 和 policy 是 session settings,不属于用户 RAW YAML。Windows VPN 固定覆盖所有应用;policy 只控制 Always On capability、本地子网旁路和目标 CIDR 旁路。

networkSettings 约束:

  • 四项都必填并且必须是对应地址族的合法单播地址;
  • TUN 地址不能与同地址族 DNS 地址相同;
  • 不能使用 unspecified、loopback、link-local、multicast,IPv4 也不能使用 broadcast;
  • 配置内容或任一地址变化时,活动会话不会 hot-swap,必须先 stopVpn;
  • 完全相同的配置、地址和 policy 重复 startVpn 是幂等查询,不创建第二个 Session Host。

policy.excludedCidrs 最多 64 项,必须是规范 network/prefix;拒绝重复、host bits、/0、禁用 IPv6 时的 IPv6 项和 VPN DNS overlap。alwaysOn 只声明 profile capability,实际自动连接仍由 Windows 用户设置和 active profile 决定。

VCore 会校验 YAML、发布 vcore-session-v2: 内容寻址 Session Snapshot,并把 token、解析后的顶层 IPv6 开关、四个地址和 policy 写入最大 4 KiB 的 profile custom configuration。调用方不要自行创建另一个 VpnPlugInProfile 或维护第二份 Snapshot。

需要让 Session Host 同会话监督 package-local 进程时,可以额外提交 sessionBackend.processes;每项只有 executableRelativePath 和 arguments。第一版不管理端口、UDP、readiness 或进程业务配置,完整契约见 Windows 会话运行时。本 demo 不携带 backend。

Manifest 契约

AppxManifest.xml.in 中以下值是当前 VCore 代码契约:

Manifest 项 必须值/规则
Application 数量 1
Session Host extension windows.fullTrustProcess / vcore-windows-session-host.exe
Provider executable vcore-windows-vpn-host.exe
Provider background EntryPoint VCore.VpnBackgroundTask
Provider runtime / trust windowsApp / appContainer
in-process server path vcore.dll
activatable class VCore.VpnBackgroundTask,ThreadingModel="both"
capabilities internetClientServer、privateNetworkClientServer、runFullTrust、networkingVpnProvider
minimum desktop OS 10.0.19042.0

可以修改 identity、publisher、版本、主 Application Id/EXE、显示名称、图标和 app execution alias。不要删除 Session Host/Provider extensions 或修改 VCore.VpnBackgroundTask。桥接还固定使用 profile 名 VCore,可选 StartupTask 固定使用 VCoreStartup;两者都按 package family 隔离。

三项 VCore 文件必须位于 package 根目录:

vcore.dll
vcore-windows-vpn-host.exe
vcore-windows-session-host.exe

不要加入 Wintun、LoopbackAccessRules 或 CheckNetIsolation exemption。Provider 的 loopback 唤醒、同包命名管道、/1 + /1 路由、DNS assignment 和物理 socket 绑定都由 VCore 管理。

已有纯 UWP UI 的接入方式

纯 UWP UI 保持 AppContainer;在同一个 MSIX 中增加独立完全信任 broker:

UWP UI
  -> AppService 或受认证的同包 IPC
  -> full-trust broker
  -> VCoreWindowsVpnInvoke

broker 负责 JSON bridge、命令串行化和结果回传。UWP UI 不接触 YAML 快照路径、VPN profile、Provider 管道或 Session Host PID。broker 也不能复用 vcore-windows-session-host.exe;Session Host 是 VCore 私有的每会话数据面进程。

本示例用 VCoreUwpDemo.exe 直接充当完全信任 broker/前台,因此没有加入产品特定的 AppService 协议、UI 和状态持久化。只有确实存在纯 UWP UI 时才增加这层 IPC。

生命周期与失败关闭

推荐宿主流程:

  1. 启动时调用 getEnvironment,确认运行在预期 package family;
  2. 调用 getVpnStatus 恢复系统真实状态;
  3. 用户连接时构造当前 YAML、四个地址和完整 policy,调用 startVpn;
  4. UI 可以退出,VPN 与 Session Host 继续;
  5. UI 重启后再次以 getVpnStatus 为权威;
  6. 用户断开时调用 stopVpn 并等待结果;
  7. 只有 Disconnected 时才安装或更新包。

不要在普通代理流失败时自动停止整个 VPN。Provider/Session Host 退出、控制或数据管道 EOF、非法协议、启动超时和物理网络变化由 VCore 自己失败关闭。

发布前检查

  • 为 ARM64 和 x64 分别构建、签名并验证同架构四产物;
  • 从无旁路开发文件的干净检出执行 locked build;
  • 在 Windows 10 20H2 与支持的 Windows 11 上执行真实 TUN 测试;
  • 验证物理 IPv4/IPv6、DNS enabled/disabled、TCP、UDP、ICMP 和 Stop 清理;
  • 执行 WACK,使用 Partner Center 正式 identity/publisher;
  • 获得受限能力审批后再提交 Store;
  • 发布记录保存 revision、lockfile、产物 hash 和签名结果,不把这些一次性值写回本示例。

详细内部契约见: