WSL - 连接到 VPN 时 DNS 不工作

WSL - 连接到 VPN 时 DNS 不工作

我已经使用 WSL Bash/Ubuntu 几年了,但由于某种原因,最近出现了这个问题。
DNS 无法解析任何内部和外部名称。我第一次重新安装 WSL 时,我认为它有效,一天......但不再有效,即使我重新安装。

从 Windows 应用商店全新安装 Ubuntu 18.04:

user@hostname:~$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, remove this line.
nameserver <DNS server from wi-fi NIC 1>
nameserver <DNS server from wi-fi NIC 2>
nameserver <DNS server from ethernet 2 (VPN) NIC 1>
search anyconnect.local

user@hostname:~$ ping google.com -c 1
ping: google.com: Name or service not known

user@hostname:~$ ping 8.8.8.8 -c 1
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=16.1 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 16.197/16.197/16.197/0.000 ms

user@hostname:~$ dig +short google.com
user@hostname:~$ dig +short @8.8.8.8 google.com
user@hostname:~$ 

修改后/etv/resolv.conf

user@hostname:~$ dig +short google.com

user@hostname:~$ cat /etc/resolv.conf
search <internal-domain>.local
search anyconnect.local
nameserver <DNS server from wi-fi NIC 1>
nameserver <DNS server from wi-fi NIC 2>
nameserver <DNS server from ethernet 2 (VPN) NIC 1>
nameserver <DNS server from ethernet 2 (VPN) NIC 2>
nameserver 8.8.8.8
nameserver 8.8.4.4

user@hostname:~$ ls -la /etc/resolv.conf
-rw-r--r-- 1 root root 167 May 28 09:18 /etc/resolv.conf

user@hostname:~$ ping google.com -c 1
ping: google.com: Name or service not known

user@hostname:~$ ping 8.8.8.8 -c 1
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=17.0 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 17.045/17.045/17.045/0.000 ms

# disconnected VPN

user@hostname:~$ dig +short google.com
172.217.21.142

user@hostname:~$ ping google.com -c 1
PING google.com (172.217.21.142) 56(84) bytes of data.
64 bytes from arn11s02-in-f14.1e100.net (172.217.21.142): icmp_seq=1 ttl=53 time=17.4 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 17.445/17.445/17.445/0.000 ms

user@hostname:~$ dig +short google.com
172.217.21.142

# connected VPN

user@hostname:~$ dig +short google.com

user@hostname:~$ ping google.com -c 1
ping: google.com: Name or service not known
user@hostname:~$ 

正如您所看到的,一旦我断开 VPN,名称解析就可以完美运行。然而,我一整天都保持连接到 VPN,显然是因为它需要连接到公司资源。

我不依赖于 WSL 上的内部 DNS,尽管理想情况下这也应该起作用,但我确实需要外部 DNS 工作。

DNS 在本地按预期工作。我可以从 VPN 网卡 ping 通 DNS 服务器,但不能从 wi-fi 网卡 ping 通 DNS 服务器。我尝试过重新安装 WSL,也尝试过仅使用 Google 的名称服务器/etc/resolv.conf。尚未更新 WSL,因为apt需要 DNS...

Windows 10 版本 1909
Ubuntu 18.04(来自 Windows 应用商店)
Cisco AnyConnect VPN(选中“连接时允许访问本地 LAN”)

有人有主意吗?从哪儿开始?

答案1

解决。

Ubuntu 子系统 (WSL) 在打开或关闭 VPN 时无法解析公司和非公司域。

固定的。

必须创建 /etc/wsl.conf 文件并添加一个条目以终止重新启动时自动生成的 resolv.conf 文件。将代码块添加到/etc/wsl.conf:

[network] 

generateResolvConf = false

然后以管理员身份打开 powershell 并运行命令来重新启动 ubuntu 子系统:

wsl --shutdown

现在,重新打开 ubuntu 子系统

按顺序使用这些命令:

cd /etc
ls

该目录应显示“resolv.conf”文件(这是一个符号链接)。该链接现在应该是红色的,表明该链接没有通向任何地方。删除resolv.conf链接并创建新的/etc/resolv.conf文件

在新的resolv.conf文件中,写入以下代码块

search    your.domain.com
nameserver    x.x.x.x
nameserver    x.x.x.x
nameserver    y.y.y.y

其中 X 是 Cisco Anyconnect VPN 适配器中配置的 DNS 地址。在网络设置中找到 Cisco VPN 适配器,右键单击 Cisco VPN 适配器并单击“属性”,现在突出显示 IPv4 并单击“属性”。然后记下首选 DNS 和备用 DNS 并将其复制到 resolv.conf 文件中。

Y 是您的普通 IPv4 DNS 地址

现在再次从 Powershell 重新启动子系统。注意:如果这不起作用,则意味着 resolv.conf 文件再次被子系统吹走。为了使其工作,系统必须读取 wsl.conf 文件。如果未读取,请尝试重新安装子系统或升级到 20.04。

答案2

请参阅此处根据与 IPv6 DNS 服务器观察到的冲突提出的解决方法:

https://github.com/microsoft/WSL/issues/1350#issuecomment-742454940

请注意一个重要事实和解决方法:

/etc/resolv.conf当另一个网络适配器正在使用时,不会添加来自 VPN 连接的 DNS 服务器IPv6 DNS 服务器,这似乎会导致某种冲突(额外的 IPv4 DNS 服务器被丢弃)。

检查使用 IPv6 DNS 服务器的适配器:

Get-DnsClientServerAddress -AddressFamily IPv6 | Where-Object ServerAddresses -NE "{}" | Select-Object -ExpandProperty InterfaceAlias

获取其相关的适配器绑定

Get-NetAdapterBinding -ComponentID ms_tcpip6 | Where-Object Name -In (Get-DnsClientServerAddress -AddressFamily IPv6 | Where-Object ServerAddresses -NE "{}" | Select-Object -ExpandProperty InterfaceAlias)

使用 Powershell 为每个适配器绑定(或直接为所有适配器)禁用 IPv6具有管理员权限

Disable-NetAdapterBinding -Name "Wi-Fi" -ComponentID ms_tcpip6 -PassThru
Disable-NetAdapterBinding -Name "Network Bridge" -ComponentID ms_tcpip6 -PassThru
...
Disable-NetAdapterBinding -Name "*" -ComponentID ms_tcpip6 -PassThru

或者,简单地在以太网/wifi 适配器上禁用 IPv6使用 Windows 用户界面:

图像

现在,启用 VPN 连接时可以正确添加名称服务器,禁用 VPN 时可以正确删除名称服务器。

连接 VPN 后:

$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 192.168.1.1
nameserver xx.xx.xx.x1 # obfuscated company dns
nameserver xx.xx.xx.x2 # obfuscated company dns
search home

VPN 断开连接时:

$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 192.168.1.1
search home

答案3

过去几天我遇到了这个问题,这让我发疯。对于我的口味来说,周围的解决方案都太老套了。我创建了一个非常简单的wsl-resolv-handler.ps1(请参阅本消息后面的脚本块),它可以根据 InterfaceMetric 自动设置正确的名称服务器顺序,创建正确的搜索行。

基本上,您可以为 VPN 接口设置较低(==较高优先级)的 InterfaceMetric,如下所示(以管理员身份启动 powershell):

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

设置好接口指标后,您可以使用下面脚本块中的脚本。脚本的顶部包含如何使用的完整说明以及一些需要正确的设置(WslDistroName 和 ResolvConfFile)。

# 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 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.
#
# 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"
#

$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
        $x = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

$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

$CommentLine = [string]::Format("# Generated by wsl-resolv-handler.ps1.")
Write-Output $CommentLine | Set-Content -Path $ResolvConfFile
$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
  }
}

Convert-To-UnixLineEndings $ResolvConfFile

Pause "Press any key to continue..."

将上述脚本保存为wsl-resolv-handler.ps1并按照注释中的说明进行操作。祝你好运 + 玩得开心(注意,这种方法应该适用于任何类型的 VPN 或网络拓扑更改,只要您正确配置它并在 Windows 任务管理器中正确设置任务,它就可以在没有手动愚蠢的情况下工作。您不需要提升权限才能运行它,只要脚本可以写入/etc/resolv.conf)!

注意:我还在此处发布了对此最相关的 github 问题的答案(有大量关于 wsl 的 resolv.conf 生成器损坏的 github 问题):https://github.com/Microsoft/WSL/issues/2884#issuecomment-928299305

答案4

这对我有用,所以希望它能减轻其他人的挫败感。

创建/etc/wsl.conf

[network] 

generateResolvConf = false

删除或备份 /etc/resolv.conf

sudo rm -f /etc/resolv.conf

从命令提示符重新启动 wsl

wsl --shutdown

启动一个新的 bash 会话,DNS 解析应该与主机上完全一样。

相关内容