Skip to content

fix(netwatch): discover Windows default routes without WMI - #226

Open
domenkozar wants to merge 4 commits into
n0-computer:mainfrom
domenkozar:fix/windows-default-route-without-wmi
Open

domenkozar wants to merge 4 commits into
n0-computer:mainfrom
domenkozar:fix/windows-default-route-without-wmi

Conversation

@domenkozar

Copy link
Copy Markdown

Description

Windows default-route discovery currently creates a WMI connection, which requires COM access. In Factorseal's restricted Windows network helper, that path terminated the process with delay-load exception 0xc06d007e during network startup.

Use the existing netdev::get_default_interface() lookup instead. This avoids WMI and returns an interface name from the same source as get_state(), matching the documented requirement that State::default_route_interface be a key in State::interfaces. Synchronous discovery stays on spawn_blocking, and lookup failures still produce a warning and None.

Remove the WMI dependency and its now-unused Windows-only chrono and serde declarations. Add a Windows test checking the route-name/map-key contract when a default route is available.

Breaking Changes

None. No public API changes.

Notes & open questions

Validation:

  • Upstream formatting configuration passes.
  • cargo test --locked -p netwatch --all-features --lib --test smoke: 17 library tests and one smoke test pass on Linux.
  • cargo xwin clippy --locked --target x86_64-pc-windows-msvc -p netwatch --all-features --all-targets -- -D warnings passes, including compilation of the new Windows test.
  • The same route-lookup change passes Factorseal's native Windows acceptance, including restricted-helper startup, restart, concurrent views, and three-device delivery through a sealed courier after the sender exits. The helper retains its LPAC token, creation-time mitigations, and job restrictions.

The new upstream Windows test has been cross-compiled locally; its native execution is left to upstream CI. Factorseal's native results exercise the downstream integration, not that new test.

Change checklist

  • Self-review.
  • Documentation updates following the style guide, where relevant.
  • Tests where relevant; validation and native-execution limits listed above.
  • All breaking changes documented (none).

@n0bot n0bot Bot added this to iroh Sep 8, 2026
@github-project-automation github-project-automation Bot moved this to 🚑 Needs Triage in iroh Sep 8, 2026
@matheus23 matheus23 moved this from 🚑 Needs Triage to 👀 In review in iroh Sep 10, 2026
matheus23
matheus23 previously approved these changes Sep 10, 2026

@matheus23 matheus23 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for this PR!

I checked

  • The error enum changes are private, so don't break the API
  • The original default_interface implementation was introduced here, there's no particular reason given why it's using WMI's RouteTable lookup vs. netdev (default-net back then).

We use default routes in iroh for checking if the network seemingly changed (e.g. Wifi to Cellular).

Do you happen to have a windows machine to test this behavior? When switching networks, you should see netwatch::netmon::Monitor::interface_change() trigger a change and have State::is_major_change relative to the past version be true.

Otherwise this LGTM.

@domenkozar

Copy link
Copy Markdown
Author

I sadly don't have access to a windows machine, I've observed this on Windows CI and fixed it along the way.

@matheus23

Copy link
Copy Markdown
Member

Hm okay. I asked dig why he introduced WMI-based route resolution specifically for windows in that old iroh PR, and he says it was because netdev wasn't as reliable.
We should do some tests on windows again to ensure we're not regressing, before we merge this.

@matheus23
matheus23 dismissed their stale review September 10, 2026 12:37

(need to run further tests on Windows)

@domenkozar

Copy link
Copy Markdown
Author

Hm okay. I asked dig why he introduced WMI-based route resolution specifically for windows in that old iroh PR, and he says it was because netdev wasn't as reliable. We should do some tests on windows again to ensure we're not regressing, before we merge this.

Not sure it counts, but I vibecoded a test in Windows CI at https://github.com/domenkozar/net-tools/actions/runs/34504089122/job/102961810876

@domenkozar

Copy link
Copy Markdown
Author

@matheus23 any chance to merge this?

@matheus23

Copy link
Copy Markdown
Member

Yeah - this is just blocked on proper testing on a windows box with network changes.

Sorry - the team was busy attending RustConf and a team retreat (and I was on vacation last week). I'll have access to a windows box next week.

@JamesLavin

Copy link
Copy Markdown

I'm writing to encourage merging this PR.

The rest of this note was generated by Claude but directly addresses a real issue we hit that forced us to remove a feature from our app on Windows builds...

Another benefit of this PR: the WMI dependency also makes netwatch impossible to build in a Tauri 2 app on Windows.

wmi 0.18.4 declares two independent wide ranges:

[target.'cfg(target_os = "windows")'.dependencies]
windows      = ">=0.59, <0.63"
windows-core = ">=0.59, <0.63"

In a graph that contains both tauri and iroh, cargo satisfies them from different windows-rs generations. Our lockfile resolves wmi to windows 0.61.3 (reused from tao 0.35.3 → tauri-runtime-wry 2.11.4 → tauri 2.11.5) together with windows-core 0.62.2 (reused from netwatch 0.19.3 ← iroh 1.2.0). wmi then fails to compile, because IWbemObjectSink comes from the 0.61 generation while #[implement], Interface and IUnknownImpl come from 0.62:

error[E0277]: the trait bound `IWbemObjectSink: windows_core::Interface` is not satisfied
   --> wmi-0.18.4/src/query_sink.rs:138:1

note: there are multiple different versions of crate windows_core in the dependency graph

That fails the entire Windows build, not just the networking code. Replacing the WMI path as this PR does removes the failure mode completely, so it would fix tauri + iroh on Windows as a side effect.

Provenance, to be clear about what we did and didn't verify: this comes from CI build logs for x86_64-pc-windows-msvc plus the resolved Cargo.lock, not from a reduced repro. Our workaround for now is to declare iroh under [target.'cfg(not(windows))'.dependencies], so Windows simply has no P2P.

@matheus23

matheus23 commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

@JamesLavin thanks for letting us know.

Do you currently have a windows machine accessible to you and can run a quick test? (I'm currently traveling this week, so don't have access to my usual machines)

Either run a specific test with netwatch main and netwatch under this PR to see how it handles network changes (e.g. switching between WiFi networks or switching from WiFi to Ethernet), or run iroh with and without this PR patched in and see if the transfer example in the iroh repository works across network changes in both versions.

@JamesLavin

Copy link
Copy Markdown

Thanks for replying, @matheus23.

I do my dev work on Mac & Linux but have a Windows laptop I can test on.

I pulled the PR branch, installed the latest Rustup, and ran cargo make test.

All tests passed, except for windows_default_route_change, which says "ignored, changes Windows routes; requires the disposable CI harness."

I can run whichever tests/commands you want, but I'm not familiar with the repo, and I put my iroh-using feature on ice yesterday because of this, so I can't currently point at this there either.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

3 participants