Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only first nameserver is used from /etc/resolv.conf when I use VPN #2884

Closed
donaldpipowitch opened this issue Jan 29, 2018 · 12 comments
Closed

Comments

@donaldpipowitch
Copy link

This bug-tracker is monitored by developers and other technical types. We like detail! So please use this form and tell us, concisely but precisely, what's up. Please fill out ALL THE FIELDS!

If you have a feature request, please post to the UserVoice.

If this is a console issue (a problem with layout, rendering, colors, etc.), please post to the console issue tracker.

Important: When reporting BSODs or security issues, DO NOT attach memory dumps, logs, or traces to Github issues. Instead, send dumps/traces to secure@microsoft.com, referencing the GitHub bug number. Ideally, please configure your machine to capture minidumps, repro the issue, and send the minidump from "C:\Windows\minidump".

  • Your Windows build number: (Type ver at a Windows Command Prompt) Microsoft Windows [Version 10.0.16299.192]

  • What you're doing and what's happening: (Copy&paste specific commands and their output, or include screen shots)

I use WSL Ubuntu and I have a /etc/resolv.conf like this one:

nameserver 172.1.2.3
nameserver 172.1.2.4
nameserver 8.8.8.8
search example.lan
  • What's wrong / what should be happening instead:

This works with the resolv.conf mentioned above when I'm NOT using VPN:

$ ping google.com
PING google.com ...
$ ping example.lan
PING example.lan ...

When I use VPN I get:

$ ping google.com
ping: unknown host google.com

The same error comes when I use this resolv.conf:

nameserver 172.1.2.3
nameserver 8.8.8.8
nameserver 172.1.2.4
search example.lan

It works when I use this resolv.conf, but now I can't ping to example.lan anymore:

nameserver 8.8.8.8
nameserver 172.1.2.3
nameserver 172.1.2.4
search example.lan

So it looks like only the first nameserver is used when I use VPN.

It works fine from the Powershell or any other non-WSL application with VPN.

  • Strace of the failing command, if applicable: (If some_command is failing, then run strace -o some_command.strace -f some_command some_args, and link the contents of some_command.strace in a gist here)

https://gist.github.com/donaldpipowitch/105b9b2f5802657593d468ae35265739

See our contributing instructions for assistance.

@sunilmut
Copy link
Member

See the section on Bash loses network connectivity once connected to a VPN https://docs.microsoft.com/en-us/windows/wsl/troubleshooting

We are looking for a better solution for supporting DNS for WSL with VPN connected.

Marking this duplicate and closing it out. Hopefully the above workaround unblocks you.

@donaldpipowitch
Copy link
Author

donaldpipowitch commented Jan 31, 2018

Thanks.

So it seems it is a duplicate of #1350, but the workaround doesn't work for me, because I have the same problem as described here: #1350 (comment)

@sunilmut
Copy link
Member

sunilmut commented Jan 31, 2018

@donaldpipowitch - Got it! We are looking at alternate solutions for DNS resolution within WSL. Hang in there.

@donaldpipowitch
Copy link
Author

Thank you 😊

@dannyk81
Copy link

dannyk81 commented Apr 1, 2018

@donaldpipowitch Check my comment here #2082 (comment)

This is a workaround I'm using for about a month and seem to work quite well.

@sunilmut not sure what kind of directions you are exploring, but I would consider using some kind of "built-in" recursor (with caching preferably) to perform the queries across the vpn dns servers and upstream servers.

@vodickavaclav
Copy link

Use this script #1350 (comment) and set proper adapter order. VPN adapter must be first.

@Spongman
Copy link

i don't understand why WSL can't just write the entries in resolv.conf in the correct order?

@rubin55
Copy link

rubin55 commented Sep 27, 2021

I ran into this n the last few days and it was driving me nuts. The solutions floating around where all WAY too hackish for my tastes. I created a very simple wsl-resolv-handler.ps1 (see script block later in this message) which can automagically set the correct nameserver order, create a correct search line, based on the InterfaceMetric.

Basically, you can set a lower (== higher priority) InterfaceMetric for your VPN interface as follows (start a powershell as admin):

> Get-NetIpInterface # Get a list of interfaces, Note the InterfaceIndex and InterfaceMetric for your VPN adapter
> Set-NetIPInterface -InterfaceIndex 12 -InterfaceMetric 10 # For example, if your VPN adapter has InterfaceIndex 12, we're setting the InterfaceMetric to 10, making sure 10 is lower than whatever you WiFi or Ethernet adapter has

After your interface metrics are set a-ok, you can use the script in the script-block below. The top of the script contains a complete explanation for how to use + a few settings (WslDistroName and ResolvConfFile) that need to be correct.

# Before attempting to run this script, review and/or follow the
# following steps.
#
# 0. Make sure you can execute powershell scripts. Start Powershell as an
#    administrator and execute:
#
#      Set-ExecutionPolicy RemoteSigned
#
# 1. Make sure you disable wsl's broken resolv.conf handler.
#    Create /etc/wsl.conf with the following 2 lines (without the pound signs):
#
#      [network]
#      generateResolvConf = false
#
#    After that, make sure you issue a wsl.exe --shutdown.
#
# 2. Configure your WSL distro name in $WslDistroName below (do wsl -l to
#    see your distro names) and make sure we're pointing at your resolv.conf
#    file in $ResolvConfFile. Also make sure we can write to the resolv.conf
#    file. I had to set permissions pretty broadly at 666 (chmod 666 /etc/resolv.conf).
#
# 3. Schedule this script with Task Scheduler:
#
#      * Click Action –> Create Task…
#      * Give your task a name in the General tab
#      * Click on the Triggers tab and then click New…
#      * In the "Begin the task" menu, choose “On an event.” Then, choose:
#
#          Log: Microsoft-Windows-NetworkProfile/Operational
#          Source: NetworkProfile
#          Event ID: 10000
#
#      * Event ID 10000 is logged when you connect to a network. Add another
#        one when a disconnect would occur (Event ID 10001):
#
#          Log: Microsoft-Windows-NetworkProfile/Operational
#          Source: NetworkProfile
#          Event ID: 10001
#
#      * Go to the Conditions tab. Make sure it runs regardless of AC adapter
#        connected/disconnected, peruse the other options there.
#
#      * Go to the Actions tab. Add a run script action and then:
#
#          Program/script: powershell.exe
#          Arguments: -NoProfile -File "c:\where\you\stored\wsl-resolv-handler.ps1"
#      
#      * Optionally add -WindowStyle Hidden to above Arguments.

$WslDistroName = "Debian"
$ResolvConfFile = [string]::Format("\\wsl$\{0}\etc\resolv.conf", $WslDistroName)

function Convert-To-UnixLineEndings($path) {
  $oldBytes = [io.file]::ReadAllBytes($path)
  if (!$oldBytes.Length) {
      return;
  }
  [byte[]]$newBytes = @()
  [byte[]]::Resize([ref]$newBytes, $oldBytes.Length)
  $newLength = 0
  for ($i = 0; $i -lt $oldBytes.Length - 1; $i++) {
      if (($oldBytes[$i] -eq [byte][char]"`r") -and ($oldBytes[$i + 1] -eq [byte][char]"`n")) {
          continue;
      }
      $newBytes[$newLength++] = $oldBytes[$i]
  }
  $newBytes[$newLength++] = $oldBytes[$oldBytes.Length - 1]
  [byte[]]::Resize([ref]$newBytes, $newLength)
  [io.file]::WriteAllBytes($path, $newBytes)
}

Function Pause ($message)
{
    # Check if running Powershell ISE
    if ($psISE)
    {
        Add-Type -AssemblyName System.Windows.Forms
        [System.Windows.Forms.MessageBox]::Show("$message")
    }
    else
    {
        Write-Host "$message" -ForegroundColor Yellow
        $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

# Discover things and create an $Entries object.
$NetworkInterfaces  = Get-NetIPInterface -AddressFamily IPv4 | Where-Object ConnectionState -EQ 'Connected' | Where-Object NlMtu -LT 9001
$DNSServerAddresses = Get-DnsClientServerAddress -AddressFamily IPv4
$DNSClients = Get-DnsClient

$Entries = $NetworkInterfaces | ForEach-Object {
  [PSCustomObject]@{
    'InterfaceAlias'      = $_.InterfaceAlias
    'InterfaceIndex'      = $_.InterfaceIndex
    'InterfaceMetric'     = $_.InterfaceMetric
    'DNSServerAddresses'  = ($DNSServerAddresses | Where-Object InterfaceIndex -EQ $_.InterfaceIndex | Where-Object AddressFamily -EQ 2).ServerAddresses
    'DNSSuffixes'  =  @(($DNSClients | Where-Object InterfaceIndex -EQ $_.InterfaceIndex).ConnectionSpecificSuffix) + @(($DNSClients).ConnectionSpecificSuffixSearchList | Out-Null)
  }
} | Sort-Object InterfaceMetric -Unique

# Tell the console what we found.
Write-Output ([string]::Format("      Resolv.conf location: {0}", $ResolvConfFile))
Write-Output ([string]::Format("    DNS servers configured: {0}", ($Entries.DNSServerAddresses -join ",")))
if ($Entries.DNSSuffixes -gt 0) {
    Write-Output ([string]::Format("Search suffixes configured: {0}", ($Entries.DNSSuffixes -join ",")))
}

# Writing resolv.conf with things discovered.
$CommentLine = [string]::Format("# Generated by wsl-resolv-handler.ps1.")
Write-Output $CommentLine | Set-Content -Path $ResolvConfFile
if ($Entries.DNSSuffixes -gt 0) {
    $SearchLine = [string]::Format("search {0}", ($Entries.DNSSuffixes -join " "))
}
Write-Output $SearchLine | Add-Content -Path $ResolvConfFile
$Entries | ForEach-Object {
  $_.DNSServerAddresses | ForEach-Object {
    $NameServerLine = [string]::Format("nameserver {0}", $_)
    Write-Output $NameServerLine | Add-Content -Path $ResolvConfFile
  }
}

# Make sure where UNIXy.
Convert-To-UnixLineEndings $ResolvConfFile

# Tell the console we're done.
Pause "Press any key to continue..."

Save the above script as wsl-resolv-handler.ps1 and follow the instructions in the comments. Good luck + have fun (note, this approach should work with any type of VPN or network topology changes, it will work without manual stupidity as long as you configure it correctly and set up the task in Windows Task Manager correctly. You don't need elevated permissions to run this, as long as the script can write to /etc/resolv.conf)!

Update: Small fix, script doesn't write an empty search line anymore when there are no DNS suffixes.

@NicolasRouquette
Copy link

For WslDistroName, do we use the name from wsl --status ?

For example:

wsl --status
Default Distribution: Ubuntu-20.04
Default Version: 2

Windows Subsystem for Linux was last updated on 7/31/2021
WSL automatic updates are on.

Kernel version: 5.10.16

c:\>wsl --list
Windows Subsystem for Linux Distributions:
Ubuntu-20.04 (Default)
docker-desktop
docker-desktop-data

Is $WslDistroName="Ubuntu-20.04" the correct setting for your script?

@rubin55
Copy link

rubin55 commented Oct 1, 2021

is $WslDistroName="Ubuntu-20.04" the correct setting for your script?

That would be correct, yes. You can also test/see this by doing something like

dir \\wsl$\Ubuntu-20.04\ in PowerShell or cmd.exe; you would then see the root filesystem of your Linux distribution.

@NicolasRouquette
Copy link

Thanks, @rubin55, I tried the script and it does indeed update /etc/resolv.conf upon being triggered by the network connect/disconnect events. I was wondering if it would help me solve the WSL2 networking problem with a full VPN (Pulse Secure); alas, it does not. I am still stuck with the same issue as #5068

@rubin55
Copy link

rubin55 commented Oct 1, 2021

Hi @NicolasRouquette, the problem that you and many users of Cisco AnyConnect and Pulse Secure are most likely running into has to do with how those VPN clients handle extra lockdown features after establishing a connection to the VPN.

The specific feature I'm talking about here is related to locking down access to other networks/subnets after a connection is established (also see here, specifically related to WSL2 with Pulse Secure): the VPN client in your case is configured to do that, which causes WSL2 based environments to be blocked (which is logical, as WSL2 is essentially a HyperV guest, on a different virtual network within your machine).

Since it's the client that is causing this (by implementing the security policy configured by the corporate VPN administrators), I would think you have a few options:

  1. Use WSL1, this way your processes are shared with the Windows host itself, and there is no other network. That's why WSL1 would work and WSL2 not
  2. Try the rather awesome OpenConnect open-source client, which currently also supports Pulse Secure networks. This client can be configured to ignore local network lockdown policies (I have actually done that, on Windows, with both Cisco AnyConnect and Pulse Secure)
  3. Talk to your corporate VPN administrators and explain the problem. Ask them to allow the local subnet your WSL2 instance is using (maybe it's even standarized? I don't know)
  4. Maybe come up with some sort of direct socket/pipe device that could be used as some sort of SOCKSy proxy? This would require some programming and evil creativeness (update: just learned about wsl-vpnkit which does just that 8-))

Personally, I like WSL1 much better exactly due to these issues. Next to that, I like to see the wsl processes in my regular tasklist.exe and I'm having a much better file-system interchange experience whilst working on files in my Windows home directory. Good luck!

@github-actions github-actions bot mentioned this issue Mar 18, 2024
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants