microsoft / microsoft/WSL

Mirrored networking: host->WSL localhost broken; loopback relay connects to wrong destination ports in the guest

Open
#41,137 7 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs-investigation network wsl2
Dominant language
C++
Stars
33.7k
Forks
1.8k
Avg merge
3d 17h
Merged PRs (30d)
116

Description

## Windows Version

Microsoft Windows [Version 10.0.26200.8894]

## WSL Version

2.9.4.0 (pre-release; also reproduced on 2.7.8.0 stable)

## Are you using WSL 1 or WSL 2?

WSL 2

## Kernel Version

6.18.35.2-1

## Distro Version

Ubuntu 26.04 LTS

## Other Software

Tailscale 1.98.9 (bug reproduces with Tailscale disconnected). No third-party AV/firewall (Defender only). No Docker.

## Repro Steps

`.wslconfig`:
```ini
[wsl2]
vmIdleTimeout=-1
networkingMode=mirrored

[experimental]
bestEffortDnsParsing=true
```

1. In WSL: `python3 -m http.server 8765 --bind ::`
2. From Windows: `curl.exe -m 4 http://127.0.0.1:8765/`

## Expected Behavior

HTTP 200 — the connection should be relayed into the WSL guest at destination port 8765.

Control machine: a second machine on the same Windows build (10.0.26200.8894), WSL 2.7.10.0, mirrored mode, same Tailscale version, works correctly.

## Actual Behavior

Connection times out. **The mirrored-mode loopback relay dials into the guest at the wrong destination ports.**

An AF_PACKET capture on `loopback0` inside the guest, during a **single** `curl.exe http://127.0.0.1:8765/` from the host, shows the relay connecting to incorrect, incrementing destination ports (never 8765), each correctly RST'd by the guest since nothing listens there:

```
TCP 127.0.0.1:65292 -> 127.0.0.1:55818 [S]
TCP 127.0.0.1:55818 -> 127.0.0.1:65292 [AR]
TCP 127.0.0.1:65292 -> 127.0.0.1:55819 [S]
TCP 127.0.0.1:55819 -> 127.0.0.1:65292 [AR]
TCP 127.0.0.1:65292 -> 127.0.0.1:55820 [S]
TCP 127.0.0.1:55820 -> 127.0.0.1:65292 [AR]
TCP 127.0.0.1:65293 -> 127.0.0.1:62562 [S]
TCP 127.0.0.1:62562 -> 127.0.0.1:65293 [AR]
TCP 127.0.0.1:65293 -> 127.0.0.1:62563 [S]
TCP 127.0.0.1:62563 -> 127.0.0.1:65293 [AR]
...
```

Not port-specific: probing a listener on port 3000 produced relay SYNs to 24142 and 24145. IPv6 (`[::1]`) fails identically. Once, transiently, a probe succeeded (HTTP 200), so the relay *can* map correctly on this machine but almost never does.

Additional diagnostics performed:

- **Host-side pktmon** (filter port 8765): the original SYN (`127.0.0.1:src -> 127.0.0.1:8765`) traverses TCPIP → WFP Native Filter → VFP Extension → VMS Ext Filter/Protocol and is last seen `Rx` at the `[VM Nic]` component, correctly addressed to the guest `loopback0` MAC; no drop counters increment anywhere.
- **Inbound from the network works perfectly**: other LAN/Tailscale hosts reach the same WSL listener on this machine's mirrored addresses. Only host→guest loopback is broken.
- **Guest plumbing verified**: `loopback0` up, `net.ipv4.conf.loopback0.route_localnet=1`, rp_filter loose, `ip rule`/table 127 (`127.0.0.1 via 169.254.x.x dev loopback0`) all present and identical to the working control machine. Empty nftables ruleset, no firewall services.
- Windows→WSL loopback traffic *counters* on `loopback0` do increment during probes — but entirely from the relay's wrong-port SYNs and the guest's RSTs.

Ruled out (verified identical to the working control machine, bug persists after each):

- Hyper-V firewall: effective (ActiveStore) VMSetting identical (`Enabled True / DefaultInboundAction Block / LoopbackEnabled True / AllowHostPolicyMerge True`); also tested with explicit `DefaultInboundAction Allow`
- `netsh interface portproxy reset` (stale NAT-era rules removed)
- Windows Defender Firewall profiles identical; NDIS adapter bindings identical (all-stock Microsoft components)
- Tailscale: same version/config as control; fails with `tailscale down`
- WSL upgrade 2.7.8.0 → 2.9.4.0 (pre-release)
- Full Windows reboot
- HNS state reset (stopped `hns`, removed `HNS.data`, reboot)

This looks like the same relay port-scrambling family as #40343 (there: WSL→host direction, SYN-ACK returned to the wrong ephemeral port; here: host→guest direction, relay dials the wrong destination port).

## Diagnostic Logs

Happy to provide the pktmon ETL/text captures, the in-guest packet captures, and `collect-networking-logs.ps1` output on request.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the mirrored-mode loopback case from `.wslconfig` with `python3 -m http.server 8765 --bind ::`, then compare the behavior with the working control machine. Review the mirrored networking loopback relay and related issue #40343; done means host requests reach the guest's actual destination port and return HTTP 200 for both IPv4 and IPv6.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
networking, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.