From inside the distro, a ping to an internal server times out while the same address answers from Windows. The VPN is connected and the Windows route is correct, so the gap is the WSL boundary. Walk the path from the failing command back to the host interface. The fix is not a fixed CIDR in a config file; it is reading the current address and adding it where the distro can use it.

Confirm where the path stops

Run the same test on both sides: resolve and connect to one internal host from Windows, then repeat it in the distro. A Windows success plus a distro timeout locates the failure between the two, not in the VPN client or the internal server. Do this before changing any route, so the two results describe the same destination.

Inside the distro, ip -4 addr shows a virtual adapter with an address from the WSL NAT range, and ip route shows a default pointing at the WSL gateway. There is no route for the corporate prefix, because the host's tunnel adapter has no counterpart inside the distro. The default gateway leads to the WSL NAT, not to the corporate network.

Adding the corporate route without first adding a local address on a reachable link produces a timeout or a network-unreachable error. The address is the part that makes the route usable, so read it first and treat the route as the second step.

Choose mirrored networking or a scripted route

Mirrored networking hands the distro the host's own interfaces, so the tunnel and its routes appear without copying. The feature depends on a recent Windows build and on networkingMode=mirrored in .wslconfig, and enabling it changes unrelated behavior such as localhost forwarding. Treat it as a platform change, not a routing tweak. If the build supports it and the side effects are acceptable, it is the shortest path.

The narrower approach keeps the default NAT and copies the tunnel address and route into the distro whenever the tunnel comes up. It works on more builds, it does not change localhost behavior, and it fails visibly when the VPN is down. The cost is a small script that has to run on each connect.

Pick one and write it down. Mixing a mirrored configuration with manual routes produces a distro with two paths to the same prefix and no clear owner for either. One documented method is easier to debug than two half-configured ones.

Pull the current tunnel details from the host

Match the adapter by MAC address rather than by name, because names change with the VPN client and the connection order. List the adapters once, note the tunnel adapter's MAC, then query its address and prefix. The MAC stays with the virtual adapter across reconnects, while the name and the interface index do not:

powershell.exe 'Get-NetAdapter | Where-Object { $_.MacAddress -eq "3C-52-82-0A-1B-7C" } | Get-NetIPAddress -AddressFamily IPv4 | Select-Object IPAddress, PrefixLength'

The gateway comes from the interface configuration. Fetch the interface index first, then read the next hop. The index can change after a reboot or an adapter reset, which is why the script should read it instead of storing it:

powershell.exe '(Get-NetAdapter | Where-Object { $_.MacAddress -eq "3C-52-82-0A-1B-7C" }).InterfaceIndex'
powershell.exe '(Get-NetIPConfiguration -InterfaceIndex 27).IPv4DefaultGateway.NextHop'

Pipe the output through tr -d '\r' before assigning it to a variable. PowerShell terminates lines with a carriage return, and without the strip the last field carries a hidden character that makes a route command fail with a confusing parse error.

Apply the address and route inside the distro

Install the tunnel address as a prefix-qualified address on the distro interface, then route the corporate block through the host's gateway:

sudo ip addr add 172.20.14.37/22 dev vpn
sudo ip route add 172.20.0.0/16 via 172.20.12.1 dev vpn

NetworkManager drops a manually configured address when the connection cycles, and no DHCP client asks for a replacement. Set the method to automatic so each reconnect refreshes the address, then bring the connection up again. A manual method looks stable until the first reconnect:

nmcli con show vpn
sudo nmcli con mod vpn ipv4.method auto
sudo nmcli con up vpn

Run both steps from the hook that starts the VPN, not from an interactive shell. A script that reads the address, adds it, adds the route and logs the values turns a recurring manual repair into a repeatable one, and the log is the first thing to read when the prefix changes.

Pin the name and prove the path

The kernel can rename the distro interface between eth1 and eth2 after a network switch, and a script written against a name then edits the wrong device. A udev rule keyed to the MAC gives the interface a stable label:

SUBSYSTEM=="net", ACTION=="add", ATTRS{address}=="3c:52:82:0a:1b:7c", NAME="vpn"

Then verify with the address, the route and a real TCP connection: ip -4 addr show dev vpn, ip route get 172.20.4.10 and a connection to a known internal port. The route lookup should name the vpn device and the source address you added.

If all three pass inside the distro and the connection still fails, the packet is leaving WSL and being dropped on the Windows side. Check the host firewall and the VPN client's own filtering before changing the script, because another route edit will not fix a packet that is already reaching the host.

Artaigilean co-cheangailte