Skip to content

Locked mode with a Podman machine on Windows - #7

Merged
Kernel-Hunter merged 10 commits into
mainfrom
fix/podman-locked-windows
Oct 19, 2026
Merged

Kernel-Hunter merged 10 commits into
mainfrom
fix/podman-locked-windows

Conversation

@Kernel-Hunter

@Kernel-Hunter Kernel-Hunter commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

mudroom network check --backend podman --mode locked hung on the windows-latest runner after "checking locked network with podman...". Diagnostic runs on the runner found three problems.

  1. The proxy listened on Windows' 127.0.0.1. A Podman machine on WSL 2 can't reach that address: host.containers.internal resolves to the machine's default gateway, which is the "vEthernet (WSL)" address.
  2. Windows Firewall drops connections from WSL to Windows unless a rule allows them.
  3. When the forwarder couldn't reach the proxy, the check container never exited. Its proxied fetches time out after 12 seconds, but Node keeps the aborted CONNECT tunnel open, so the script printed its results and kept running while podman run waited for it.

The first fix for (1) read the gateway with podman machine ssh "ip -4 route" and fell back to 127.0.0.1 if that failed. On the runner it failed every time, and nothing said so. Once the error was shown, it read: fork/exec C:\Windows\System32\OpenSSH\ssh.exe: The handle is invalid. On Windows, Foundation maps FileHandle.nullDevice to a NUL handle that it doesn't mark inheritable, so every command Mudroom captured got an invalid stdin. Most programs never touch it, but Podman hands its stdin to ssh.exe, and that fails. With this fixed, the proxy listens on the gateway and the firewall rule is the only setup needed.

Changes:

  • On Windows, ProcessRunner.capture gives the child an empty file as stdin instead of FileHandle.nullDevice.

  • On Windows with Podman, the proxy listens on the machine's default gateway and accepts only that subnet, both read from ip -4 route in the machine. If the routes can't be read, or the gateway isn't an address on this PC (user-mode networking), Mudroom stops with an error that says so. It no longer falls back to 127.0.0.1, which the machine can't reach.

  • On Windows with Podman, the forwarder tries one connection to the proxy before the sandbox starts. If that fails, Mudroom stops, names the address the forwarder tried and the one the proxy listens on, and prints the rule to add from an administrator PowerShell:

    New-NetFirewallRule -DisplayName 'Mudroom proxy' -Direction Inbound -Action Allow -Protocol TCP -Program 'C:\path\to\mudroom.exe'

    The README gives the same rule with -Program (Get-Command mudroom).Source.

  • NetworkCheck.run has a timeout of 300 s, since starting a container on a Podman machine is slow. On timeout it removes the container and fails with a message. The DNS lookup in the check script has its own 5 s limit, and the script exits as soon as its output is flushed.

  • macOS, Linux and Docker Desktop on Windows behave as before.

  • CI: the windows-sandbox job runs the locked check without a firewall rule (it has to fail with the hint), adds the program rule, then runs the locked check and a session with diff and apply. If that fails, a later step prints the firewall rules, dropped packets and WSL routes.

Not tested: Docker Desktop on Windows, a Podman machine with user-mode networking, and how the firewall prompt behaves on a desktop PC.

NetworkCheck.run ran its container with no timeout, so a stuck runtime
left `mudroom network check` waiting with nothing on screen. It now gets
two minutes, like NetworkProbe: on timeout the container is removed and
the check fails with a message. The script's DNS lookup also gives up
after 5 seconds, so every probe in it is bounded on its own.
With Podman on Windows the locked check hung after printing its results.
The forwarder can't reach the proxy there, so the proxied fetches time
out, and Node keeps the aborted CONNECT tunnel to the forwarder open and
doesn't exit. `podman run` then waits on a container that never stops.
The same happens on macOS with a proxy that accepts and never answers:
the results are out after about 45 seconds and Node is still running at
200. The script now exits once its output is flushed.
The proxy listened on 127.0.0.1, as on macOS, but a Podman machine on
WSL 2 can't reach Windows' loopback. `host.containers.internal` points at
the machine's default gateway, the "vEthernet (WSL)" address. On Windows
with Podman the proxy now listens there and accepts only that subnet,
read from `ip -4 route` in the machine. If the gateway isn't an address on
this PC (user-mode networking, no machine), it falls back to 127.0.0.1.

Windows Firewall drops connections from WSL to Windows unless a rule
allows them, so the forwarder now tries one connection to the proxy
before the sandbox starts and, if it fails, stops with the
New-NetFirewallRule command to run. macOS, Linux and Docker Desktop are
unchanged.

CI now runs the locked check without a rule (it must fail with the hint),
adds the rule, and runs the locked network check and session.
A passing open check took 72 seconds on the Windows runner, most of it
starting the container, and the next run went past 120 and failed.
If `podman machine ssh "ip -4 route"` failed, or its output didn't parse,
the proxy quietly listened on 127.0.0.1, which a Podman machine on WSL 2
can never reach, and the only symptom was a timeout blamed on the
firewall. Now that is an error with the command's output. The
unreachable-proxy error also says which address the sidecar tried and
where the proxy was listening, and the firewall hint prints the path
with backslashes.
`podman machine ssh "ip -4 route"` failed under Mudroom with "fork/exec
C:\Windows\System32\OpenSSH\ssh.exe: The handle is invalid." Foundation
maps FileHandle.nullDevice to a NUL handle that it doesn't mark
inheritable, so the child got an invalid stdin, and podman couldn't hand
it to ssh.exe. The proxy then listened on 127.0.0.1, out of the Podman
machine's reach. Captured commands on Windows now read an empty file.

Also stop falling back to 127.0.0.1 when the machine's gateway isn't an
address on this PC (user-mode networking): say so instead.
@Kernel-Hunter
Kernel-Hunter merged commit 095f175 into main Oct 19, 2026
10 checks passed
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.

1 participant