Internet connection and DNS routing are broken from WSL2 instances, when some VPNs are active.
The root cause seems to be that WSL2 and the VPN use the same IP address block, and the VPN routing clobbers WSL2's network routing.
This problem is tracked in multiple microsoft/WSL issues including, but not limited to:
Permanently changing the IP address block used by WSL2 appears to prevent the routing conflict that breaks WSL2 networking.
More details and instructions in this gist: (Thanks @mikegerber for the explanation)
Below is my original solution of modifying the VPN interface metric each time the VPN connects
Preferably, use the WSL subnet change above for a permanent fix.
The workaround breaks down into two problems:
- Network connection to internet
- DNS in WSL2
When the VPN connection is active, network traffic out of WSL2 is not passed to the internet.
Changing the Interface Metric 1 -> 6000 for AnyConnect VPN Adapter resolves the connection issue, but this has to be done after each time the VPN connects.
By default, the Interface Metrics for AnyConnect are:
- IPv6: 6000
- IPv4: 1
ping
times out from WSL Shell.
Changing the Interface Metrics for AnyConnect to:
- IPv6: 6000
- IPv4: 6000
ping
to IP Addresses succeed, but still no DNS Resolution.
When the VPN is active, the autogenerated /etc/resolv.conf
does not work. The list of nameservers must be manually built to include some sane default DNS Name Servers and the DNS from the VPN.
First, disable automatically generating /etc/resolv.conf
.
Add the following configuration, or create the file if it doesn't exist. The path to this file is from the shell prompt of your WSL2 instance.
/etc/wsl.conf
[network]
generateResolvConf = false
Next, manually add the corportate DNS Server as the first nameserver
in /etc/resolv.conf
.
/etc/resolv.conf
nameserver <corporateDNS1>
nameserver <corporateDNS2>
nameserver 1.1.1.1
To get <corporateDNS>
addresses, use ipconfig /all
from CMD
or Powershell
prompt, and check the details of the VPN adapter:
Description . . . . . . . . . . . : Cisco AnyConnect Secure Mobility Client Virtual Miniport Adapter for Windows x64
Physical Address. . . . . . . . . : XX-XX-XX-XX-XX-XX
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes
IPv6 Address. . . . . . . . . . . : xxxx:xxxx:xxxx:xxxx(Preferred)
Link-local IPv6 Address . . . . . : xxxx:xxxx:xxxx:xxxx(Preferred)
IPv4 Address. . . . . . . . . . . : 10.20.30.40(Preferred)
Subnet Mask . . . . . . . . . . . : 255.255.255.255
Default Gateway . . . . . . . . . : ::
0.0.0.0
DHCPv6 IAID . . . . . . . . . . . :
DHCPv6 Client DUID. . . . . . . . :
DNS Servers . . . . . . . . . . . : 123.45.67.89 <- Corporate DNS 1
123.45.67.90 <- Corporate DNS 2
Primary WINS Server . . . . . . . : xxx.xx.xxx.xx
NetBIOS over Tcpip. . . . . . . . : Enabled
To automate this, I put the PS command in a script and created a Scheduled Task to run every time there is a network change.
First, create the script. I have a 'scripts' directory in my Windows user home, so I put it at:
%HOMEPATH%\scripts\UpdateAnyConnectInterfaceMetric.ps1
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000
You can save it where you want, just make sure to use that path in step 13 below.
- Open 'Task Scheduler'
- Click "Create Task" on Right Sidebar
- Name: Update Anyconnect Adapter Interface Metric for WSL2
- Set Security Options
- Check box: 'Run with highest priveleges'
- Select 'Triggers' Tab
- Click 'New' at bottom of Window
- Open 'Begin the task' drop-down
- Select 'On an Event'
- Configure Event:
- option 1: Trigger on any Network Change
- Log: 'Microsoft-Windows-NetworkProfile/Operational'
- Source: 'NetworkProfile'
- Event ID: '10000'
- option 2: Trigger only when AnyConnect Client successfully connects to VPN
- Anyconnect 4.x
- Log: 'Cisco AnyConnect Secure Mobility Client'
- Source: 'acvpnagent'
- Event ID: '2039'
- Anyconnect 5.x
- Log: 'Cisco Secure Client - AnyConnect VPN'
- Source: 'csc_vpnagent'
- Event ID: '2039'
- Anyconnect 4.x
- option 1: Trigger on any Network Change
- Click 'OK'
- Select 'Actions' Tab
- Click 'New'
- Configure Action:
- Action: 'Start a Program'
- Program/script: 'Powershell.exe'
- Add arguments: '-ExecutionPolicy Bypass -File %HOMEPATH%\scripts\UpdateAnyConnectInterfaceMetric.ps1'
- Click 'OK'
- Select 'Conditions' Tab
- Uncheck box:
- Power -> Start the task only if the computer is on AC Power
- Click 'OK'
When AnyConnect finishes connecting, a Powershell window pops up for a couple seconds and WSL can reach the network.
Hi, I'm using Windows 11 with Cisco AnyConnect. As of a day or so ago my WSL connections to hosts that I access through the VPN has begun failing with the error "no route to host".
I don't believe this is related to DNS in my case because running
nslookup <hostname>
on either the Windows machine in PowerShell or on the bash prompt in Ubuntu under WSL gives me IPs on the 192.168.x.x range (and the IPs are the same in either case). I believe they are VPC hostnames. Moreover, when I runipconfig /all
there are no DNS Servers listed under the AnyConnect adapter. I am able to access these VPC hostnames from Windows proper when I am connected to the VPN and I cannot access them when I am not connected to the VPN.When I first boot my machine, I tried to make sure that AnyConnect does not start by turning the "Cisco AnyConnect User Interface" setting off in Settings -> Apps -> Startup. I am a little concerned that the "User Interface" means that the app may have started ahead of some UI components but I am not really sure. I am thinking about this because of this comment.
After booting I open up a WSL terminal window.
Next up I start a PowerShell instance as Admin and run
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000
. I have ensured that this changes the correct AnyConnect IPv4 InterfaceMetric value to 6000.Finally I run
Restart-Service LxssManager
from the same PowerShell. This closes my WSL terminal instance, so I open up another one.In case it matters, I have taken steps to ensure that my
/etc/resolv.conf
is not auto-generated at WSL startup time. I believe thegenerateResolvConf = false
behavior under thenetwork
INI option in/etc/wsl.conf
in the version of WSL I use is buggy and I can't recall exactly how I managed to achieve this bit of behavior, but I did - theresolv.conf
contents don't change between reboots, they don't contain comments about auto-generation, and they are what I have manually set them to, which is nothing interesting: a couple ofnameserver
entries from my WiFi adapter and asearch
entry with that same adapter's Connection-specific DNS Suffix as the value.Still, after all of this, I am unable to access the VPC hostnames from WSL; I get "no route to host" errors. I reiterate that I can access these hostnames from Windows proper, and I was able to access them from WSL until very recently. In examining my bash history (I keep timestamps) I see that I ran
apt-get upgrade
within the last 24 hours so that may be it.I have gone through several blog posts and GitHub Gist and Issue comment threads, and I'm at a complete loss. If anyone has any suggestions I would love to hear them. Thank you.
Cisco AnyConnect Version: 4.8.01090
Windows Version: 10.0.22000
wsl.exe
Version: 10.0.22000.653 (found using this technique)--
Edit: I have filed an issue with the WSL project. Feel free to follow along here: microsoft/WSL#8811