* 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.
14 KiB
VCore Invoke API
业务接口版本为 5,配置结构修订版为 27。配置只通过内联的 configYaml 或 configYamls 传入;每份已加载的 VCore 运行时最多拥有一个公共实例。代理组实时选择沿用 Controller,不增加 Invoke method 或版本协商。静态 ECH 只使用节点内联配置,不新增 bootstrap DNS 入参。
C ABI
char *VCoreInvoke(const char *request_json);
#ifdef _WIN32
char *VCoreWindowsVpnInvoke(const char *request_json);
#endif
void VCoreFree(char *response);
- 请求必须是以 NUL 结尾的 UTF-8 JSON。
- 非空响应由 VCore 分配,调用方必须使用同一库中的
VCoreFree释放。 - 非法输入、未知方法、状态错误和 panic 返回合法失败 JSON;只有灾难性分配失败可以返回
NULL。 - 业务运行时线程不能重入 Invoke;Debug 和 Release 构建都立即返回失败 JSON,包括
version等只读请求。 - 请求正文、响应正文、完整配置、UUID、密钥、short ID 和凭据不得写入日志。
VCoreWindowsVpnInvoke是 Windows 安装包桥接接口,不属于业务 API v5。VCoreWindowsVpnInvoke当前在调用线程上初始化 MTA;调用线程必须尚未初始化 COM,或已经是 MTA。STA/ASTA 调用不受支持。
请求与响应
请求:
{
"apiVersion": 5,
"method": "getState",
"instanceId": "1",
"payload": {}
}
成功响应:
{"success":true,"data":{},"error":""}
失败响应:
{"success":false,"data":null,"error":"invalid configuration"}
约束:
apiVersion必填且只能为5。method必须来自本文列出的白名单。payload必须是对象;无参数时传{}。- 运行时级方法必须省略
instanceId;实例级方法必须携带 VCore 返回的非空 ID。 - 未知 envelope 字段和未知 payload 字段都会失败。
- 无业务数据的方法成功时返回空对象,不返回
null。 - Invoke envelope 最大 3 MiB,单份 YAML 最大 256 KiB。
初始化与生命周期
每份已加载的 VCore 运行时先调用:
{
"apiVersion": 5,
"method": "initialize",
"payload": {"dataDir": "/absolute/path"}
}
dataDir 必须是可写绝对路径。VCore 固定使用:
<dataDir>/configs # 宿主可选持久化目录,不是 Invoke 输入
<dataDir>/geodata # VCore 管理的 GeoData 目录
同一路径重复初始化幂等,切换路径失败。
公共实例状态:
stopped -> preparing -> prepared -> starting -> running
^ |
+------------- stopping <-------------+
关键数据面提前退出 -> failed
instanceId是当前运行时内不可复用的代次令牌,不代表支持并行公共实例。- 同一实例一次只执行一个生命周期命令,重叠命令立即失败。
validateConfig是可并发的纯校验方法。measureDelay使用独立批次和私有工作器,不进入公共实例表。- 不支持配置热重载;切换配置需要
stop -> prepare -> start。唯一的运行期路由变更是通过 Controller 修改静态select组的当前选择,它不修改已 prepare 的配置。 stop在 stopped 状态幂等;destroyInstance是最终同步清理屏障。
方法
version
运行时级方法:
{"apiVersion":5,"method":"version","payload":{}}
返回:
{
"apiVersion": 5,
"buildIdentity": "VCore;engine=rust;coreVersion=0.1.0;invokeApiVersion=5;configVersion=27",
"configVersion": 27,
"engine": "rust",
"version": "0.1.0"
}
configVersion 是二进制报告的结构修订号,不是 YAML 字段。源码 revision 和产物 hash 由发布系统记录。
initialize
参数和幂等语义见“初始化与生命周期”。成功时返回规范化后的 dataDir。
getGeoDataState
运行时级只读方法,要求已经初始化:
{"apiVersion":5,"method":"getGeoDataState","payload":{}}
返回 geosite 和 geoip 两项:
{
"geosite": {
"required": true,
"available": false,
"updating": false,
"lastSuccess": null,
"nextCheck": null,
"lastError": null,
"etag": null,
"hash": null
},
"geoip": {
"required": false,
"available": false,
"updating": false,
"lastSuccess": null,
"nextCheck": null,
"lastError": null,
"etag": null,
"hash": null
}
}
时间使用 Unix 秒,hash 为小写 SHA-256。调用不会创建实例、联网或改变更新调度。
createInstance
{"apiVersion":5,"method":"createInstance","payload":{}}
返回:
{"instanceId":"1"}
该方法只创建 stopped 状态记录。实例销毁前再次创建失败。
destroyInstance
实例级方法:
{"apiVersion":5,"method":"destroyInstance","instanceId":"1","payload":{}}
实例仍处于 prepared、running 或 failed 时,先执行与 stop 等价的清理。取得命令锁后,无论清理成功、失败或 panic,ID 都会永久失效;只有因 busy 在取得命令锁前被拒绝时,实例才保留。
validateConfig
运行时级方法:
{
"apiVersion": 5,
"method": "validateConfig",
"payload": {"configYaml": "proxies:\n - name: edge\n ...\n"}
}
完成大小、YAML、结构、共享 route-target 命名空间、引用和字段组合校验。节点的 dialer-proxy 可引用节点或组;全部上游和组成员边(包括未选成员)统一做无环校验。不创建实例、不解析远端域名、不联网,也不读取 GeoData。资产缺失不影响纯配置校验。
prepare
实例级方法,只允许 stopped 状态:
{
"apiVersion": 5,
"method": "prepare",
"instanceId": "1",
"payload": {"configYaml": "proxies:\n - name: edge\n ...\n"}
}
- 读取当时可用的本地 GeoData,不启动或等待下载。
- 为所有潜在物理首跳执行引导 DNS:节点无上游,或其上游组经纯组成员链能选到 DIRECT 时,预解析节点服务器及独立 VLESS 下载端点,包括尚未选中的 DIRECT 路径。候选解析失败则 prepare 失败;仅经代理访问的域名交给下一跳。切换 DIRECT 不新增系统 DNS。
- 校验每个静态
select组的初始选择;省略default-selected时使用第一项,显式值必须是直接成员。可变的 session 选择状态到start时才创建。 - 成功进入 prepared;失败释放临时资源并回到 stopped。
- 含 TUN 的配置从 preparing 起持有运行时本地的 TUN/protect 租约,直到停止或销毁。
- Android 只有在实际启用 TUN 时才要求事先注册 protect controller。
start
Apple 和 Android 的 TUN 启动参数:
{
"apiVersion": 5,
"method": "start",
"instanceId": "1",
"payload": {"tunFd":23,"tunFraming":"utun"}
}
Android 使用 rawIp。非 TUN 配置必须省略 tunFd 和 tunFraming。
tunFd由宿主借用,宿主必须预先设置 nonblocking。- VCore 校验后建立带
CLOEXEC的副本,只关闭副本。 - Apple 只接受
utun,Android 只接受rawIp。 - 从 prepared 配置创建本次 session 的代理组选择状态。
- 所有监听器和关键数据面成功后才进入 running。
- GeoData 更新只在启动后按需后台运行,不属于启动关键路径。
- Windows 系统 VPN 使用安装包桥接接口,不使用文件描述符启动参数。
stop
{"apiVersion":5,"method":"stop","instanceId":"1","payload":{}}
同步取消并等待监听器、Controller、TUN、netstack、DNS、会话、出站和更新任务,关闭 VCore 持有的文件描述符副本并释放平台回调租约。返回后不得继续产生数据包或调用 protect callback;本次 session 的代理组选择随之销毁。
getState
{"apiVersion":5,"method":"getState","instanceId":"1","payload":{}}
返回:
{"state":"running","lastError":""}
异步数据面失败时状态为 failed,lastError 只包含有界且脱敏的摘要。
measureDelay
运行时级方法:
{
"apiVersion": 5,
"method": "measureDelay",
"payload": {
"configYamls": ["proxies:\n - name: edge\n ...\n"],
"timeout": 5,
"url": "https://cp.cloudflare.com/"
}
}
返回顺序与输入一致:
{
"results": [
{"success":true,"delay":123,"error":""},
{"success":false,"error":"measureDelay probe failed"}
]
}
configYamls接受 1–5 份非空节点配置,timeout为 1–30 秒。- 同一运行时一次只允许一个测速批次,最多并发五个私有工作器。
- 节点配置顶层只允许
proxies,不接受proxy-groups;dialer-proxy也只能引用具体节点。VCore 推导唯一链头,且该链必须覆盖全部节点。 - 工作器只准备出站图并执行 TCP、可选 TLS 和 HTTP/1.1 HEAD;不创建公共实例、监听器、TUN、DNS、规则、嗅探器或 GeoData。
- 宿主测量组成员时,按当前选择快照展开具体链后提交;上游选到 DIRECT 时移除相应
dialer-proxy,选到 REJECT 时不发起该项测量。该快照不改变运行中的组选择。 - URL 必须是无 userinfo 和 fragment 的绝对 HTTP/HTTPS URL;HTTPS 使用发布信任根。
- 任意合法 HTTP 状态都表示探测成功;不跟随重定向、不读取正文。
- 单项失败不取消其他项;方法返回前释放全部私有任务。
Android protect
Android TUN 通过 Invoke 之外的运行时本地回调注册:
ProtectFd(fd) -> bool
- 含 TUN 的实例必须在
prepare前注册;非 TUN 和measureDelay不需要。 - 每个出站 TCP/UDP socket 在 connect 前同步调用 protect。
- 返回 false、抛出异常或 controller 失效都会使当前连接失败关闭。
- 回调必须快速、同步、非阻塞,且不能重入 Invoke 或注册接口。
- TUN 租约存活期间不能替换或注销 controller;
stop/destroyInstance是释放屏障。 - Android binding 使用 UTF-8
byte[],不依赖 Modified UTF-8。
Controller
配置 external-controller 后,运行时可提供回环 GET /traffic、GET /group、GET /group/{name}、GET /proxies/{name} 和 PUT /proxies/{name}。代理组 Controller 可以在非 TUN 的 HTTP 或 SOCKS5 配置中运行;此时 /traffic 不存在。只要 Controller 管理代理组,secret 就必填并保护全部路由。
组成员列表是配置期固定的,选择只存于当前 Running Session。成功切换只影响之后新建的物理 TCP、UDP 和 DNS transport,不迁移既有连接、UDP association、DNS 状态或 TCP pool,也不触发 failover。已认证 Hysteria2 会话的后续逻辑流和跳端口 socket 保留初始上游选择;新的认证会话才读取新选择。Controller 查询不携带 instanceId,不进入 Invoke 命令锁;完整语义见 Controller API。
Windows 安装包桥接
VCoreWindowsVpnInvoke 使用独立的桥接修订版 3:
{"bridgeVersion":3,"method":"getVpnStatus","payload":{}}
只接受六个方法:
getEnvironmentgetVpnStatusstartVpnstopVpngetStartupTaskStatussetStartupTaskEnabled
startVpn 的 payload 为:
{
"configYaml": "tun:\n enable: true\n...",
"networkSettings": {
"ipv4Address": "192.168.3.1",
"ipv6Address": "fd00::2",
"dnsIpv4Address": "8.8.8.8",
"dnsIpv6Address": "2001:4860:4860::8888"
},
"policy": {
"alwaysOn": false,
"allowLocalNetwork": true,
"excludedCidrs": []
},
"sessionBackend": {
"processes": [
{
"executableRelativePath": "bin\\proxy-core.exe",
"arguments": ["run", "--mode", "vpn"]
}
]
}
}
policy 始终必填。Windows VPN 固定覆盖所有应用;alwaysOn 控制 profile capability,实际自动连接仍取决于 Windows 用户设置和 active profile;allowLocalNetwork 控制本地子网是否绕过;excludedCidrs 是最多 64 个规范 IPv4/IPv6 目标网段。拒绝重复项、host bits、/0、禁用 IPv6 时的 IPv6 项,以及包含当前 VPN DNS 地址的项。
sessionBackend 可以省略。存在时包含 1..=8 个有序关键进程;每项只有 package installed location 内的规范 .exe 相对路径和有界 argv 数组。同一可执行文件可出现多次。第一版不接受 port、UDP、readiness、restart、environment、working directory 或 raw command line;任一进程退出都会使当前 VPN 会话失败关闭。
桥接把 YAML、进程顺序、路径和参数发布为 vcore-session-v2:<sha256> Session Snapshot。参数引用的文件由调用方保持存在且不可变,VCore 不读取或摘要其内容。getVpnStatus.data.snapshotToken 返回该完整 Session token。
桥接请求最大 1 MiB。它负责安装包身份、单一 VPN profile、不可变 Session Snapshot、连接/断开命令和系统 VPN 状态;Provider 负责激活 Session Host。桥接不公开 profile CRUD、内部文件路径、backend 描述、参数、PID、管道名称或 Snapshot 维护。数据包、Controller 流量查询、代理组查询/切换和业务生命周期不经过该 JSON 桥接。
编码与安全边界
- 所有 JSON DTO 拒绝未知字段。
- 配置、错误和日志按 UTF-8 字节计数并受固定上限约束。
- TUN 原始数据包解析最大 1,500 字节;最终代理 UDP 响应按有效 MTU 减去 48 字节限制,其他 TUN 平台最大 1,452 字节,Windows 最大 1,352 字节。
- 嵌套 UDP 协议可以增加有界帧头,但解封装后的最终负载仍受该平台响应上限限制。
- 节点和代理组定义名共享大小写敏感的严格 UTF-8 命名空间;
DIRECT、REJECT和RULES不能用作定义名。 - Secret、password、UUID、REALITY key、short ID、目标地址和完整配置不得进入日志。