Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Workaround for WSL2 network broken on VPN

Overview

Internet connection and DNS routing are broken from WSL2 instances, when some VPNs are active. The workaround breaks down into two problems:

  1. Network connection to internet
  2. DNS in WSL2

This problem is tracked in multiple microsoft/WSL issues including, but not limited to:

Network connection

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.

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

Automatically update Interface Metric

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.

Save the script in a file

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.

Create the scheduled task:

  1. Open 'Task Scheduler'
  2. Click "Create Task" on Right Sidebar
  3. Name: Update Anyconnect Adapter Interface Metric for WSL2
  4. Set Security Options
    • Check box: 'Run with highest priveleges'
  5. Select 'Triggers' Tab
  6. Click 'New' at bottom of Window
  7. Open 'Begin the task' drop-down
  8. Select 'On an Event'
  9. 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
      • Log: 'Cisco AnyCOnnect Secure Mobility Client'
      • Source: 'acvpnagent'
      • Event ID: '2039'
  10. Click 'OK'
  11. Select 'Actions' Tab
  12. Click 'New'
  13. Configure Action:
    • Action: 'Start a Program'
    • Program/script: 'Powershell.exe'
    • Add arguments: '-ExecutionPolicy Bypass -File %HOMEPATH%\scripts\UpdateAnyConnectInterfaceMetric.ps1'
  14. Click 'OK'
  15. Select 'Conditions' Tab
  16. Uncheck box:
    • Power -> Start the task only if the computer is on AC Power
  17. Click 'OK'

When AnyConnect finishes connecting, a Powershell window pops up for a couple seconds and WSL can reach the network.

@xxmlud
Copy link

xxmlud commented Apr 26, 2022

Hi @machuu ,

Of course, I have run the script with the Administrator console.

Then I opened wsl2 with Ubuntu but it still doesn't work.
What version of Cisco client are you using?

Regards

@murchu27
Copy link

murchu27 commented Apr 26, 2022

What value is at the end of this line in your UpdateAnyConnectInterfaceMetricLow.ps1 script? 1 or 6000?

Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric {1 or 6000?}

The script that you run to enable internet access on WSL should use the 6000 value!

@xxmlud
Copy link

xxmlud commented Apr 26, 2022

Hi @murchu27 ,

I had it set to value 1.
I have modified it and set the value to 6000 but I still have no output to the internet.

Do you think there is some step that I have left out?

Regards

@murchu27
Copy link

murchu27 commented Apr 26, 2022

What is the output from running that script? Is it just this one line, and then a bunch of hyphens?

ifIndex InterfaceAlias AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp ConnectionState PolicyStore

If so, then I think something might be up with the naming of your AnyConnect interface. Can you run Get-NetIPInterface in PowerShell and post the result?

@machuu
Copy link
Author

machuu commented Apr 26, 2022

@xxmlud,

What version of Cisco client are you using?
I changed jobs last year, and using a mac now.

@xxmlud
Copy link

xxmlud commented Apr 26, 2022

Hello

Sorry, the result has not been pasted well.

In the output of the script you can see how the value is set to 6000 in the AnyConnect interface, it seems that the script is working well.

→ C:\Windows\system32› Get-NetIPInterface

 
ifIndex InterfaceAlias                  AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp     ConnectionState PolicyStore


13      Local Area Connection* 2        IPv6                  1500              25 Enabled  Disconnected    ActiveStore

22      Local Area Connection* 1        IPv6                  1500              25 Disabled Disconnected    ActiveStore

1       Loopback Pseudo-Interface 1     IPv6            4294967295              75 Disabled Connected       ActiveStore

11      Ethernet 5                      IPv4                  1367            6000 Disabled Connected       ActiveStore

15      Ethernet 4                      IPv4                  1500              35 Enabled  Connected       ActiveStore

73      vEthernet (WSL)                 IPv4                  1500            5000 Disabled Connected       ActiveStore

9       Ethernet 2                      IPv4                  1500              35 Enabled  Disconnected    ActiveStore

13      Local Area Connection* 2        IPv4                  1500              25 Disabled Disconnected    ActiveStore

17      Bluetooth Network Connection    IPv4                  1500              65 Enabled  Disconnected    ActiveStore

22      Local Area Connection* 1        IPv4                  1500              25 Enabled  Disconnected    ActiveStore

14      Ethernet                        IPv4                  1500               5 Enabled  Disconnected    ActiveStore

19      Wi-Fi                           IPv4                  1500              25 Enabled  Disconnected    ActiveStore

1       Loopback Pseudo-Interface 1     IPv4            4294967295              75 Disabled Connected       ActiveStore

 

→ C:\Windows\system32› .\UpdateAnyConnectInterfaceMetricLow.ps1

 

ifIndex InterfaceAlias                  AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp     ConnectionState PolicyStore


11      Ethernet 5                      IPv6                                  6000                          Persiste...

11      Ethernet 5                      IPv4                                  6000                          Persiste...

11      Ethernet 5                      IPv4                  1367            6000 Disabled Connected       ActiveStore

Indeed, the script works fine.
The ethernet5 is the interface used by Cisco.

Regards

@murchu27
Copy link

murchu27 commented Apr 26, 2022

Okay, after running the script, try running wsl --shutdown from PowerShell. Then run bash to start wsl, and try to run ping 8.8.8.8

@xxmlud
Copy link

xxmlud commented Apr 26, 2022

Still not working

→ C:\Windows\system32› .\UpdateAnyConnectInterfaceMetricLow.ps1

ifIndex InterfaceAlias                  AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp     ConnectionState PolicyStore
------- --------------                  ------------- ------------ --------------- ----     --------------- -----------
11      Ethernet 5                      IPv6                                  6000                          Persiste...
11      Ethernet 5                      IPv4                                  6000                          Persiste...
11      Ethernet 5                      IPv4                  1367            6000 Disabled Connected       ActiveStore


→ C:\Windows\system32›
→ C:\Windows\system32› wsl --shutdown
→ C:\Windows\system32› bash
root@LAP-PF2ZHBXK-SP:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
8 packets transmitted, 0 received, 100% packet loss, time 7318ms

root@LAP-PF2ZHBXK-SP:~#

@murchu27
Copy link

murchu27 commented Apr 26, 2022

Maybe try curl https://google.com, I've found ping can be dodgy even when internet access is working.

@573
Copy link

573 commented Apr 26, 2022

@xxmlud could you please try Restart-Service LxssManager after running the script ?

Note: Personally I stick to toggle the vpn via key shortcuts for now as the metrics trick doesn't solve the issue of lacking internal network resources. Still I'm gathering further intel on this whole topic (routes etc.) here: https://gist.github.com/573/c91b0a0a64a2652e0fa75a65abb28349

@xxmlud
Copy link

xxmlud commented Apr 27, 2022

Hi @573 @murchu27,

Thank you for your intentions.

→ C:\Windows\system32› .\UpdateAnyConnectInterfaceMetricLow.ps1

ifIndex InterfaceAlias                  AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp     ConnectionState PolicyStore
------- --------------                  ------------- ------------ --------------- ----     --------------- -----------
11      Ethernet 5                      IPv6                                  6000                          Persiste...
11      Ethernet 5                      IPv4                                  6000                          Persiste...
11      Ethernet 5                      IPv4                  1367            6000 Disabled Connected       ActiveStore

→ C:\Windows\system32› Restart-Service LxssManager
→ C:\Windows\system32› wsl --shutdown
→ C:\Windows\system32› bash
root@THINKPAD:~# curl google.es
curl: (6) Could not resolve host: google.es
root@THINKPAD:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
23 packets transmitted, 0 received, 100% packet loss, time 22847ms

root@THINKPAD:~#

I have tried restarting the LxssManager service as well, but it still does not work.

@regwhitton
Copy link

regwhitton commented May 5, 2022

Thanks for the info.

Running the powershell script from the scheduled task did not work for me, because company admin policies prevent it. Discovered this by experiments running the powershell command with a -NoExit argument.

Worked around it by putting the commands from the script directly into the arguments. So step 13 becomes:

Configure Action:
Action: 'Start a Program'
Program/script: 'Powershell.exe'
Add arguments: '-Command Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000'

@xxmlud
Copy link

xxmlud commented May 5, 2022

Hi @regwhitton,

what version of the client are you using?

@regwhitton
Copy link

regwhitton commented May 5, 2022

@xxmlud - I'm using 4.10.01075

I would suggest testing your script by opening a powershell as administrator and from run:

powershell.exe -NoExit -ExecutionPolicy Bypass -File <full-path-to-script>\script.ps1

With the -NoExit argument the window stays open and you can see the error message.

Also, I opened the Task Scheduler and set up the task as an administrator.

@TonyBrookILSTU
Copy link

TonyBrookILSTU commented May 9, 2022

@xxmlud
Copy link

xxmlud commented May 9, 2022

Hi @regwhitton,

I upgraded my Cisco AnyConnect version to 4.9.06037 and the workaround worked for me.

The only problem I had was configuring the task in the scheduled tasks.

But what I did was to generate a .vbs script that calls the .ps1 and this way it worked for me.

Thank you all very much!

@mkorangestripe
Copy link

mkorangestripe commented May 11, 2022

Remember to add a search line to /etc/resolv.conf to resolve hosts without the FQDN.

$ host web2prd2
web2prd2.yourcompany.com has address 10.67.16.109

PS C:> ipconfig /all | find "DNS Suffix Search List"
DNS Suffix Search List. . . . . . : yourcompany.com

/etc/resolv.conf:
nameserver 10.xx.xx.xxx
nameserver 10.xx.xx.xxx
nameserver 1.1.1.1
search yourcompany.com

@corymichaelmurray
Copy link

corymichaelmurray commented Jun 9, 2022

So this workaround only worked once for me - due to corporate restrictions I can't set an automatic job to run the script, but I can run it manually. Anything I may be missing since this only has worked out once?

@regwhitton
Copy link

regwhitton commented Jun 10, 2022

@corymichaelmurray - I also had the issue with corporate policy preventing the script from running. However, I was able to put the contents of the script directly on the command line. See my comment above.

@MarcusLang-art
Copy link

MarcusLang-art commented Jun 19, 2022

It's not just the proxy that matters, but the pula proxy. Many factors have a big impact on the effectiveness of your pula proxy. If you misconfigure the pula for your project, you'll likely find that your proxies are blocked, and you can no longer access the target website. So it's much better than a regular proxy. I also advise you to check out web scraping. Based on your request, I've used their services, and I think that's exactly what would work for you. Also, didn't specify what proxies you plan to use: public, shared, or dedicated? They're different in quality, after all.

@narsimhamchelluri-ds
Copy link

narsimhamchelluri-ds commented Sep 8, 2022

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 run ipconfig /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 the generateResolvConf = false behavior under the network 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 - the resolv.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 of nameserver entries from my WiFi adapter and a search 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)

# dpkg -l '*wsl*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version                Architecture Description
+++-==============-======================-============-=================================================================
ii  ubuntu-wsl     1.450.2                amd64        Ubuntu on Windows tools - Windows Subsystem for Linux integration
ii  wslu           2.3.6-0ubuntu2~20.04.0 all          collection of utilities for the Windows 10 Linux Subsystem

--

Edit: I have filed an issue with the WSL project. Feel free to follow along here: microsoft/WSL#8811

@Lucascoorek
Copy link

Lucascoorek commented Sep 16, 2022

The easiest workaround for this problem is this package: https://github.com/sakai135/wsl-vpnkit 🚀

@573
Copy link

573 commented Sep 27, 2022

The easiest workaround for this problem is this package: https://github.com/sakai135/wsl-vpnkit 🚀

Absolutely 🚀 I can confirm that, tested and proofing it works - here is my steps to reproduce - not necessarily all needed:
EDIT: Striked out the points that are not needed as precautions (tested with the release as of this comments date)
My other WSL2 instance started already
AnyConnect running but disconnected
Installed https://github.com/sakai135/wsl-vpnkit and run in foreground all checks green
Connected via AnyConnect to VPN
ping google.com in my other WSL2 instance still worked 🦄
Outside WSL2:

  • Accessing enterprise bitbucket still worked
  • Accessing enterprise jira still worked
  • Doing full mvn build of enterprise software still worked
  • Accessing internal enterprise mailserver still worked

All that in no time using no brain at all 😆

Not working but not important in my case: Accessing internal enterprise ressource from within WSL2 instance via domain name if name server is enterprise one. Access the resource via IP if really needed.

@machuu
Copy link
Author

machuu commented Sep 27, 2022

@573 / @Lucascoorek,

At the time I wrote this, I tried wsl-vpnkit, but it didn't fix the routing issue. That was ~2 years ago, so things may have changed.

@573
Copy link

573 commented Sep 27, 2022

@573 / @Lucascoorek,

At the time I wrote this, I tried wsl-vpnkit, but it didn't fix the routing issue. That was ~2 years ago, so things may have changed.

Tried latest commit / release, so ...

@Sandv
Copy link

Sandv commented Oct 5, 2022

Wow. This works. Thank you so much!

@pypycodes
Copy link

pypycodes commented Oct 19, 2022

Tested OK. Flawless

@bisand
Copy link

bisand commented Nov 4, 2022

It worked perfectly! Thanks!

@luisbunuel
Copy link

luisbunuel commented Nov 18, 2022

Have you tried the option in the Cisco AnyConnect client "Allow local (LAN) access when using VPN (if configured)" ?
It works for me, you dont need to modify the interfaces metrics and let WSL to manage the resolv.conf file.

@573
Copy link

573 commented Nov 18, 2022

Have you tried the option in the Cisco AnyConnect client "Allow local (LAN) access when using VPN (if configured)" ? It works for me, you dont need to modify the interfaces metrics and let WSL to manage the resolv.conf file.

This works when the admins in your enterprise enabled that switch and also in certain cases internal resources those visible only to enterprise members are invisible when using the switch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment