Skip to content

Mirrored networking: reply from TUN-based VPN adapter dropped before reaching WSL vNIC #41443

Description

@mateus2k2

Windows Version

Microsoft Windows [Version 10.0.26200.9168]

WSL Version

2.7.12.0

Are you using WSL 1 or WSL 2?

  • WSL 2
  • WSL 1

Kernel Version

6.18.33.2-2

Distro Version

Ubuntu 24.04.3 LTS (Noble Numbat)

Other Software

Viscosity 1.13.1 (build 1.13.1.1884) — OpenVPN-based VPN client for Windows (https://www.sparklabs.com/viscosity/), configured as a standard dev tun (layer-3, point-to-point) client profile, pull-filter ignore redirect-private (split tunnel — only the remote's specific subnet is routed, not a full-tunnel default route).

Repro Steps

  1. .wslconfig:
    [wsl2]
    networkingMode=mirrored
    firewall=true
    [experimental]
    hostAddressLoopback=true

  2. Connect a Viscosity VPN profile on the Windows host that uses a dev tun (layer-3) adapter — not dev tap. Example: remote gateway 10.9.0.1, client address 10.9.0.2 on a /24, with a pushed route to a remote subnet (192.168.211.0/24) reachable only through the tunnel.

  3. Confirm the VPN works from the Windows host itself: ping 192.168.211.68 succeeds (TTL 63, ~20ms).

  4. Start WSL (wsl -d Ubuntu). Confirm the VPN adapter is mirrored in:
    ip addr show

eth4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
inet 10.9.0.2/24 brd 10.9.0.255 scope global noprefixroute eth4

  1. From WSL: ping 10.9.0.1 (the VPN's own directly-connected gateway) → fails with Destination Host Unreachable (source 10.9.0.2, i.e. generated locally, packet never left the machine).
  2. ip neigh show dev eth410.9.0.1 dev eth4 INCOMPLETE (ARP never resolves).
  3. Ruled out as a config/timing issue:
  • firewall=false in .wslconfig → no change.
  • Fully reconnecting the VPN before starting WSL (so mirroring should pick up an already-healthy adapter) → no change, same INCOMPLETE result.
  • net.ipv4.conf.{all,default,eth4}.arp_ignore=1 inside WSL → no change.
  • Manually forcing WSL's ARP resolution with a static neighbor entry pointing at WSL's own internal placeholder MAC (00:11:22:33:44:55, the MAC WSL's DNS-tunneling/relay channel uses on every mirrored interface):
    sudo ip neigh replace 10.9.0.1 lladdr 00:11:22:33:44:55 dev eth4 nud permanent
    
    This does change the symptom (WSL no longer blocks the packet locally — no more "Destination Host Unreachable"), but still 100% packet loss. See the packet capture below for why.
  1. Windows host's own ARP table for the same gateway is a null MAC (expected for a tun adapter — Windows never does real L2/ARP for it either, it routes to it directly at L3 as a point-to-point interface):
    arp -a
    Interface: 10.9.0.2 --- 0x1d
    10.9.0.1 00-00-00-00-00-00 dinâmico

  2. Captured with pktmon (admin PowerShell) filtered on 10.9.0.1 / 192.168.211.68, with the static neighbor entry from step 7 in place, while pinging 10.9.0.1 from WSL:
    pktmon filter add -i 10.9.0.1
    pktmon filter add -i 192.168.211.68
    pktmon start --etw -c -m real-time

Result: the ICMP echo request is seen leaving WSL, traversing the relay chain (components 178→59→25→26→2→61→3→204), and the VPN gateway does reply — the reply is seen arriving back through components 204→3→61 (real host-side relay/tunnel chain). It is then dropped twice in a row before reaching WSL's vNIC:
Solte: ... Direction Tx , tipo IP , componente 150, DropReason IPSNPI: No Ethernet header
Solte: ... Direction Rx , tipo IP , componente 143, DropReason ICMP: inspection drop
Solte: ... Direction Rx , tipo IP , componente 143, DropReason INET: transport endpoint was not found
Solte: ... Direction Rx , tipo IP , componente 143, DropReason Inspection drop

Expected Behavior

WSL should be able to reach the VPN's directly-connected gateway (10.9.0.1) and anything routed through it (e.g. 192.168.211.68), matching what the Windows host itself can already do over the same tunnel — consistent with the documented purpose of mirrored networking mode (WSL shares the host's network reachability) and with Microsoft's own prior acknowledgment of this class of bug (KB5067036 regression / KB5074109 fix, "mirrored networking in WSL could fail" with VPN virtual interfaces). This machine is on a build newer than KB5074109 (10.0.26200.9168), so the originally-documented regression is not the (or not the only) cause here.

At minimum, the reply packet actually returned by the VPN gateway (confirmed via pktmon, see step 9) should not be silently dropped by the host's own relay/callout chain (IPSNPI: No Ethernet header) before it reaches the mirrored WSL vNIC.

Actual Behavior

WSL cannot reach the VPN gateway or anything behind it, even though:

  • The VPN is fully healthy on the Windows host (ping succeeds, TTL 63).
  • The interface is correctly mirrored into WSL with the right IP/route (ip route get 192.168.211.68 correctly resolves via 10.9.0.1 dev eth4).
  • The VPN gateway does reply to WSL's request — confirmed via pktmon, the ICMP echo reply is seen arriving back through the host's relay chain (components 204/3/61).

The reply is then dropped before delivery to WSL's mirrored vNIC, root-caused via pktmon to:
componente 150, DropReason IPSNPI: No Ethernet header

i.e. the relay driver needs to wrap the reply (which arrives as a bare L3/IP packet, since it came off a tun adapter with no real Ethernet layer) into an Ethernet frame to hand to WSL's mirrored interface, and has no destination MAC to use — because no genuine ARP/L2 resolution ever happens for this adapter on either side (the Windows host's own ARP table entry for the same gateway is also a null MAC, 00-00-00-00-00-00 — Windows itself never does real L2 for this adapter, it just routes to it directly).

This means the failure is not fixable from the WSL/guest side — no sysctl, static ARP/neighbor entry, or routing change in WSL changes the outcome, since the packet is dropped by the Windows-side relay driver before it ever reaches WSL's virtual NIC. Tested and ruled out:

  • net.ipv4.conf.*.arp_ignore=1 inside WSL
  • Static ip neigh entry in WSL for the gateway
  • firewall=true/false in .wslconfig
  • Connecting the VPN before starting WSL (rules out mirroring a stale/pre-VPN adapter state)
  • Full Windows reboot (also unrelated: uncovered a separate NAT-mode regression on this machine — networkingMode=mirrored removed left WSL with zero internet, no Get-NetNat object was ever created for WSL's NAT subnet; reverting to mirrored mode restored general connectivity, unrelated to this VPN-specific issue and not otherwise reported here)

The only workaround is running the VPN client inside WSL directly (bypassing the Windows-side relay entirely), which is not always viable (e.g. splitting VPN access between Windows-native apps and WSL).

Diagnostic Logs

WslLogs-2026-08-25_19-48-49.tar.gz

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions