WSL2 uses a random network from the 172.16.0.0/12 RFC1918 private IP address block. And our VPN uses that address block, too, with a route metric of 1 (= most preferred.)
This breaks networking for WSL2. Meh!
While messing around with the interface/route metric of the VPN network may work around the problem, it also reduces the priority of the VPN. We do not really want this. Additionally, changing the interface metric does not seem to be permanent, so it requires more work when it breaks again.
A better solution is configuring WSL2 to not use a network in the VPN network space at all. However, in our case, the VPN routed all the available RFC1918 address space... (Isn't IPv4 great!)
But we can use the link-local address space from 169.254.0.0/16 and so have at least a semi-elegant and permanent solution!
- These PowerShell commands set the NAT network used by WSL2 to a subnet of 169.254.0.0/16 - I chose 169.254.214.0/24 here - and need to be run as a Windows administrator:
Set-ItemProperty `
-Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss `
-Name NatNetwork `
-Value "169.254.214.0/24"
Set-ItemProperty `
-Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss `
-Name NatGatewayIpAddress `
-Value "169.254.214.1"-
Reboot (I couldn't be bothered to check if restarting some service suffices.)
-
After the reboot, you a. should get an error message the first time you start your WSL2 (because it can't use the IP it used before the change) and b. networking should work, now with shiny new 169.254.x.y addresses.
- The only thing that makes this "semi-elegant" is that I would prefer using a network from RFC1918.
- To check the current values, run
Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss. - I've also seen DNS break a lot and would recommend checking IPv4 connectivity through the WSL2 NAT without DNS first (e.g.
ping -n 8.8.8.8or similar), then fixing DNS, if needed. My WSL just auto-configured169.254.x.1in/etc/resolv.conf, and that worked here. So WSL2 seems to have a built-in DNS proxy, but I couldn't find any documentation on it. - Our VPN set up does not route all traffic through it, so this might be not be a complete solution in that case. It would be interesting to see how a Cisco AnyConnect VPN with default route to the VPN sets this default route - what metric does the route have?
I hope this helps you, this configuration makes it so you don't have to run the script every time, it does it automatically when starting your Linux in WSL.
Definitive Manual: wsl-vpnkit Automation with systemd
This manual details the process to install and automate wsl-vpnkit as a service within a Linux distribution in WSL. It covers both scenarios with internet connection and without it.
Prerequisites
Step Zero: What to do if you don't have internet in WSL?
This step is only if when attempting "Step 1" commands like wget or apt-get fail due to lack of connection. Here we'll establish a temporary connection.
pwsh
Move to the folder where the downloaded file is located
cd $env:USERPROFILE\Downloads
Import wsl-vpnkit as a temporary distro using the relative path
wsl --import wsl-vpnkit-temp --version 2 "$env:USERPROFILE\wsl-vpnkit-temp" "wsl-vpnkit.tar.gz"
Start the network service from this temporary distro
wsl.exe -d wsl-vpnkit-temp --cd /app wsl-vpnkit
Step 1: Installation and Script Preparation
Now, within your main distro (e.g., Ubuntu), download and prepare the necessary files.
Create a dedicated folder:
mkdir -p ~/wsl-vpnkit-script && cd ~/wsl-vpnkit-script
Install dependencies:
sudo apt-get update && sudo apt-get install -y iproute2 iptables iputils-ping dnsutils wget
Download and extract wsl-vpnkit:
wget https://github.com/sakai135/wsl-vpnkit/releases/download/v0.4.1/wsl-vpnkit.tar.gz
tar --strip-components=1 -xf wsl-vpnkit.tar.gz app/wsl-vpnkit app/wsl-gvproxy.exe app/wsl-vm app/wsl-vpnkit.service
rm wsl-vpnkit.tar.gz
Step 2: systemd Service Creation and Configuration
Configure systemd to manage the scripts as an automatic service.
Copy the service file to the systemd directory:
sudo cp ./wsl-vpnkit.service /etc/systemd/system/
Edit the service file:
sudo nano /etc/systemd/system/wsl-vpnkit.service
Replace all the file content with the following configuration. Remember to change YOUR_USER to your Linux username.
[Unit]
Description=wsl-vpnkit
After=network.target
[Service]
Working directory where the scripts are located
WorkingDirectory=/home/YOUR_USER/wsl-vpnkit-script
Command to execute the script and its variables
ExecStart=/bin/sh -c "VMEXEC_PATH=$(pwd)/wsl-vm GVPROXY_PATH=$(pwd)/wsl-gvproxy.exe ./wsl-vpnkit"
Restart the service if it fails
Restart=always
KillMode=mixed
[Install]
WantedBy=multi-user.target
Step 3: Service Activation and Management
Activate the service so it starts automatically with your distro.
Enable automatic startup:
sudo systemctl enable wsl-vpnkit
Start the service now:
sudo systemctl start wsl-vpnkit
Verify it's working:
systemctl status wsl-vpnkit
Look for the green line that says active (running). If it appears, you have successfully completed!
Final note: If you completed "Step Zero", once the systemd service is active (running) in your main distro, you can now close the PowerShell window of the temporary service and, if desired, remove the temporary distro with the command in PowerShell: wsl --unregister wsl-vpnkit-temp.