Skip to content

feat(windows): add global VPN policy - #5

Merged
yiguodev merged 5 commits into
mainfrom
feat/windows-global-vpn-policy
Sep 1, 2026
Merged

feat(windows): add global VPN policy#5
yiguodev merged 5 commits into
mainfrom
feat/windows-global-vpn-policy

Conversation

@yiguodev

@yiguodev yiguodev commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • upgrade the Windows host bridge and package artifact contract to revision 3 and the VPN profile configuration to revision 4
  • add one strict all-application policy with Always On, local-network bypass, and canonical IPv4/IPv6 destination exclusions
  • keep Invoke v5, schema 13, Snapshot v2, packet-channel v1, and the existing three-process trust boundaries unchanged
  • use MTU 1400 / frame size 1412 for StartWithMainTransport, including the Windows Session Host netstack
  • derive the Windows TUN/XUDP and DNS UDP response ceiling from the effective MTU (1352 bytes)
  • read interface indexes, socket source candidates, and every preferred on-link prefix from one adapter snapshot; link-local prefixes remain route inventory rather than socket sources
  • subtract explicit exclusions from generated local inclusion routes so exclusions retain precedence

Automated validation

  • cargo fmt --all -- --check
  • cargo build --locked --all-targets
  • cargo test --locked --all-features --all-targets
  • repository-standard Clippy
  • vcore-netstack tests and Clippy
  • C header, TLS dependency, Python script, Ruff, formatting, shell syntax, and diff checks
  • Windows ARM64 release artifacts built with revision-3 manifest/hash validation

Focused tests cover 1400-MTU TUN/XUDP and DNS response budgets, WinSock address conversion, link-local route inventory, multiple addresses, distinct and duplicate IPv4/IPv6 on-link prefixes, and explicit exclusions overlapping generated child prefixes.

Windows 11 ARM64 gate

On Windows 11 ARM64 build 26200.9278, the development-signed single-Application MSIX built from the current source passed:

  • stable IPv4-only and dual-stack lifecycle, Provider/Session Host activation, stop, and cleanup
  • TCP, UDP, ICMPv4, and cache-cleared hostname traffic in both address modes; ICMPv6 in dual-stack mode
  • cache-cleared hostname traffic with runtime DNS both enabled and disabled in both address modes
  • null IPv6 client-address assignment when ipv6: false
  • local-network bypass enabled and disabled; disabled dual-stack mode installed the two expected link-local inclusion routes while retaining normal traffic, and the live LAN peer selected a /25 VPN route
  • IPv4 destination exclusion on the physical route while control traffic remained tunneled
  • Always On enable/readback/disable
  • system-profile cold activation without a bridge start call
  • invalid-policy pre-activation rejection and Session Host termination fail-close
  • zero Provider, Session Host, route, and VPN-interface residue after harness cleanup

The host has no non-link-local physical IPv6 address or IPv6 default gateway. Windows 10, native x64, physical IPv6 exclusion, production signing, WACK, restricted-capability approval, Partner Center, and Store submission remain release gates and are not claimed here.

Copilot AI balanced review requested due to automatic review settings September 1, 2026 09:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The Windows routing and lifecycle changes still require the acknowledged clean-reboot policy validation.

Pull request overview

Adds a strict global Windows VPN policy while preserving existing runtime and process boundaries.

Changes:

  • Upgrades bridge/profile contracts to revisions 3/4.
  • Adds Always On, local-network bypass, and CIDR exclusions.
  • Aligns Windows VPN and Session Host MTU at 1400.
File summaries
File Description
src/windows/vpn.rs Applies policy routes and MTU settings.
src/windows/session.rs Sets Session Host netstack MTU.
src/windows/profile.rs Persists and validates policy revision 4.
src/windows/policy.rs Implements strict policy and CIDR validation.
src/windows/mod.rs Exposes policy module and MTU constant.
src/windows/host.rs Accepts policy through bridge revision 3.
scripts/tests/test_scripts.py Updates artifact revision assertion.
scripts/src/vcore_scripts/tun2socks.py Updates demo bridge requests and policy.
scripts/src/vcore_scripts/builds.py Emits artifact contract revision 3.
readme/README.zh_CN.md Documents the revised Windows contract.
readme/README.ru.md Documents the revised Windows contract.
README.md Documents policy and Windows MTU.
include/vcore.h Updates bridge revision documentation.
example/windows-uwp/README.md Documents policy integration.
example/windows-uwp/demo.cpp Uses bridge revision 3 and default policy.
docs/windows-vpn.md Defines routing, policy, and MTU behavior.
docs/windows-session-runtime.md Updates profile and startup contracts.
docs/tun-platform.md Documents Windows policy and MTU boundaries.
docs/runtime-resource-policy.md Clarifies Windows resource limits.
docs/invoke-api.md Documents bridge revision 3 payloads.
CONTEXT.md Defines Windows VPN policy terminology.
Review details
  • Files reviewed: 21/21 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings September 1, 2026 11:10
@yiguodev

yiguodev commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Windows 11 ARM64 clean-host policy gate

Validated follow-up commit 8942611ece14e05296d819b0d4224e21b94f6d83 on Windows 11 ARM64 build 26200.9278 after a reboot. Before installation, package-owned routes, interfaces, Provider processes, and Session Host processes were all zero.

Root causes confirmed by same-source A/B packages

  • Dual-stack connected, while IPv4-only repeatedly failed with 0x8007000E. The only successful change was passing a null IPv6 client-address argument to StartWithMainTransport when IPv6 is disabled; an empty collection is not accepted on this host.
  • A loopback-bound managed main transport caused destination exclusions to bypass the Provider but time out. Binding the local managed transport to the selected physical address made Windows select the physical route.
  • Clearing ExcludeLocalSubnets alone did not override the more-specific physical on-link route. Two one-bit-longer inclusion prefixes covering that subnet made allowLocalNetwork:false capture the same LAN peer.

Final source-tree package results

  • IPv4-only: stable start/status/stop, one Provider, one Session Host, one VPN interface, bidirectional TCP traffic, Provider ingress/egress observed.
  • Dual-stack VPN interface: stable start/status/stop, one Provider, one Session Host, two VPN interfaces, bidirectional TCP traffic, Provider ingress/egress observed.
  • LAN bypass enabled: live LAN peer selected the physical route and did not open a VCore SOCKS connection.
  • LAN bypass disabled: the same peer selected the VPN route and opened a VCore SOCKS connection; public bidirectional traffic still passed.
  • IPv4 destination exclusion: excluded traffic selected the physical address/route and succeeded; a non-excluded control remained tunneled and succeeded.
  • Always On: the real profile read back alwaysOn:true while connected, remained disconnected after explicit Stop, and read back false after rebuilding with the default policy.
  • Cold profile activation: with no Provider or Session Host running, a direct Windows profile connect (no bridge startVpn) activated both processes and passed bidirectional traffic from the retained profile/Snapshot.
  • Failure gates: malformed policy was rejected before native activation; terminating Session Host caused fail-closed disconnect and route/interface cleanup.
  • Every case ended with zero Session Host, VPN route, and VPN interface residue. The stopped AppContainer Provider shell can remain resident; the harness explicitly terminates it between cases.

Validation package SHA-256: 3ee60b36d59629b04554a5dbc2d5aa6263326252689ea9f5a98d7d374f318bda

ARM64 artifacts:

  • vcore.dll: 47ec175f942191f3e7290eb031d5916cb639d2cf4dd322d26b61b607704e8213
  • Provider: 2eb553e0babed50cb5c43b2ab3d4ff3511b4c8b5d43bbd93be460c1879431894
  • Session Host: 2115216d320cc4af954f237b153b95771a58775085156d51d6a130914544f25b

Local validation also passed cargo test --locked --all-features --all-targets, repository-standard Clippy with -D warnings, formatting, ARM64 release build, and package signature verification.

Still not run: physical IPv6 destination exclusion (host has no physical IPv6/default gateway), Windows 10, native x64, WACK, restricted-capability approval, Partner Center, and production signing.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Route construction can bypass intended policy semantics, and the acceptance record contradicts the reported validation status.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

src/windows/vpn.rs:1003

  • These child inclusion routes are more specific than the physical prefix, but that also makes them more specific than an accepted exclusion covering the same local subnet. For example, with physical 198.51.100.0/24, allowLocalNetwork: false, and excluded 198.51.100.0/24, the generated /25 inclusions win and the exclusion does not bypass the VPN. Either reject this policy conflict or construct routes so explicit exclusions retain precedence.
        if let (Some(address), Some(prefix @ 1..=31)) = (physical.ipv4, physical.ipv4_prefix) {
            let child_prefix = prefix + 1;
            let network = u32::from(address) & (u32::MAX << (32 - u32::from(prefix)));
            let second = network | (1 << (32 - u32::from(child_prefix)));
            for network in [network, second].map(Ipv4Addr::from) {
  • Files reviewed: 22/22 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread docs/acceptance.md
Comment thread src/windows/vpn.rs Outdated
Copilot AI review requested due to automatic review settings September 1, 2026 11:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The acceptance document claims a clean-reboot gate passed even though the PR description says it remains pending.

Review details

Suppressed comments (1)

docs/acceptance.md:124

  • This records the clean-reboot lifecycle and policy gate as passed, but the PR description explicitly says that gate is still pending because the test host remains contaminated and StartWithMainTransport returns 0x800704C7. Acceptance records are the source of truth for executed validation, so these unexecuted success claims must be removed or replaced with the pending status before merging.
### 全局 VPN policy 与 IPv4-only clean gate(2026-09-01)

当前 Windows 11 ARM64 build 26200.9278 主机重启后,先确认 package-owned route、interface 和进程均为零,再用同一源树构建、开发签名并安装单 Application MSIX。实际结果:
  • Files reviewed: 23/23 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 1, 2026 12:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The 1,400-byte netstack still advertises a 1,452-byte TUN UDP response budget, causing oversized replies to be dropped.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 23/23 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/windows/session.rs
Comment thread README.md Outdated
Copilot AI review requested due to automatic review settings September 1, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad WinRT lifecycle, routing, and physical-network changes require final human review despite substantial test and device validation.

Review details
  • Files reviewed: 26/26 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@yiguodev
yiguodev merged commit fb1b53f into main Sep 1, 2026
2 checks passed
@yiguodev
yiguodev deleted the feat/windows-global-vpn-policy branch September 1, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants