WSL - 连接到 VPN 时 DNS 不工作

Mor*_*ten 15 linux dns vpn windows-subsystem-for-linux

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

从 Windows Store 全新安装 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:~$ 
Run Code Online (Sandbox Code Playgroud)

修改后/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:~$ 
Run Code Online (Sandbox Code Playgroud)

如您所见,一旦我断开 VPN 连接,我的名称解析就会完美无缺。但是,我全天都与 VPN 保持连接,这显然是因为它需要连接到公司资源。

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

DNS 在本地按预期工作。我可以从 VPN NIC ping DNS 服务器,但不能从 wi-fi NIC ping DNS 服务器。我试过重新安装 WSL,也试过在/etc/resolv.conf. 尚未根据aptDNS 要求更新 WSL ...

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

谁有想法?从哪儿开始?

小智 17

请参阅此处基于与 IPv6 DNS 服务器观察到的冲突的解决方法:

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

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

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

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

Get-DnsClientServerAddress -AddressFamily IPv6 | Where-Object ServerAddresses -NE "{}" | Select-Object -ExpandProperty InterfaceAlias
Run Code Online (Sandbox Code Playgroud)

获取其相关的适配器绑定

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

使用具有管理员权限的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
Run Code Online (Sandbox Code Playgroud)

或者,只需使用 Windows UI禁用以太网/wifi 适配器上的 IPv6 :

图像

现在,启用 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Blu*_*408 13

解决。

打开或关闭 vpn 时,Ubuntu 子系统 (WSL) 无法解析企业和非企业域。

固定的。

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

[network] 

generateResolvConf = false
Run Code Online (Sandbox Code Playgroud)

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

wsl --shutdown
Run Code Online (Sandbox Code Playgroud)

现在,重新打开 ubuntu 子系统

按顺序使用这些命令:

cd /etc
ls
Run Code Online (Sandbox Code Playgroud)

该目录应显示“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
Run Code Online (Sandbox Code Playgroud)

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

Y 是您的普通 IPv4 DNS 地址

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


Rub*_*ons 6

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

\n

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

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

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

\n
# Before attempting to run this script, review and/or follow the \n# following steps.\n#\n# 0. Make sure you can execute powershell scripts. Start Powershell as an\n#    administrator and execute:\n#\n#      Set-ExecutionPolicy RemoteSigned\n\n# 1. Make sure you disable wsl\'s broken resolv.conf handler.\n#    Create /etc/wsl.conf with the following 2 lines (without the pound signs):\n#\n#      [network]\n#      generateResolvConf = false\n#\n#    After that, make sure you issue a wsl.exe --shutdown.\n#\n# 2. Configure your WSL distro name in $WslDistroName below and make sure we\'re\n#    pointing at your resolv.conf file in $ResolvConfFile. Also make sure we can write \n#    to the resolv.conf file. I had to set permissions pretty broadly at 666.\n#\n# 3. Schedule this script with Task Scheduler:\n#\n#      * Click Action \xe2\x80\x93> Create Task\xe2\x80\xa6\n#      * Give your task a name in the General tab\n#      * Click on the Triggers tab and then click New\xe2\x80\xa6\n#      * In the "Begin the task" menu, choose \xe2\x80\x9cOn an event.\xe2\x80\x9d Then, choose:\n#\n#          Log: Microsoft-Windows-NetworkProfile/Operational\n#          Source: NetworkProfile\n#          Event ID: 10000\n#\n#      * Event ID 10000 is logged when you connect to a network. Add another\n#        one when a disconnect would occur (Event ID 10001):\n#\n#          Log: Microsoft-Windows-NetworkProfile/Operational\n#          Source: NetworkProfile\n#          Event ID: 10001\n#\n#      * Go to the Conditions tab. Make sure it runs regardless of AC adapter\n#        connected/disconnected, peruse the other options there.\n#\n#      * Go to the Actions tab. Add a run script action and then:\n#\n#          Program/script: powershell.exe\n#          Arguments: -noprofile -file "c:\\where\\you\\stored\\wsl-resolv-handler.ps1"\n#\n\n$WslDistroName = "Debian"\n$ResolvConfFile = [string]::Format("\\\\wsl$\\{0}\\etc\\resolv.conf", $WslDistroName)\n\nfunction Convert-To-UnixLineEndings($path) {\n  $oldBytes = [io.file]::ReadAllBytes($path)\n  if (!$oldBytes.Length) {\n      return;\n  }\n  [byte[]]$newBytes = @()\n  [byte[]]::Resize([ref]$newBytes, $oldBytes.Length)\n  $newLength = 0\n  for ($i = 0; $i -lt $oldBytes.Length - 1; $i++) {\n      if (($oldBytes[$i] -eq [byte][char]"`r") -and ($oldBytes[$i + 1] -eq [byte][char]"`n")) {\n          continue;\n      }\n      $newBytes[$newLength++] = $oldBytes[$i]\n  }\n  $newBytes[$newLength++] = $oldBytes[$oldBytes.Length - 1]\n  [byte[]]::Resize([ref]$newBytes, $newLength)\n  [io.file]::WriteAllBytes($path, $newBytes)\n}\n\nFunction Pause ($message)\n{\n    # Check if running Powershell ISE\n    if ($psISE)\n    {\n        Add-Type -AssemblyName System.Windows.Forms\n        [System.Windows.Forms.MessageBox]::Show("$message")\n    }\n    else\n    {\n        Write-Host "$message" -ForegroundColor Yellow\n        $x = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")\n    }\n}\n\n$NetworkInterfaces  = Get-NetIPInterface -AddressFamily IPv4 | Where-Object ConnectionState -EQ \'Connected\' | Where-Object NlMtu -LT 9001\n$DNSServerAddresses = Get-DnsClientServerAddress -AddressFamily IPv4\n$DNSClients = Get-DnsClient\n\n$Entries = $NetworkInterfaces | ForEach-Object {\n  [PSCustomObject]@{\n    \'InterfaceAlias\'      = $_.InterfaceAlias\n    \'InterfaceIndex\'      = $_.InterfaceIndex\n    \'InterfaceMetric\'     = $_.InterfaceMetric\n    \'DNSServerAddresses\'  = ($DNSServerAddresses | Where-Object InterfaceIndex -EQ $_.InterfaceIndex | Where-Object AddressFamily -EQ 2).ServerAddresses\n    \'DNSSuffixes\'  =  @(($DNSClients | Where-Object InterfaceIndex -EQ $_.InterfaceIndex).ConnectionSpecificSuffix) + @(($DNSClients).ConnectionSpecificSuffixSearchList | Out-Null)\n  }\n} | Sort-Object InterfaceMetric -Unique\n\n$CommentLine = [string]::Format("# Generated by wsl-resolv-handler.ps1.")\nWrite-Output $CommentLine | Set-Content -Path $ResolvConfFile\n$SearchLine = [string]::Format("search {0}", ($Entries.DNSSuffixes -join " "))\n  Write-Output $SearchLine | Add-Content -Path $ResolvConfFile\n$Entries | ForEach-Object {\n  $_.DNSServerAddresses | ForEach-Object {\n    $NameServerLine = [string]::Format("nameserver {0}", $_)\n    Write-Output $NameServerLine | Add-Content -Path $ResolvConfFile\n  }\n}\n\nConvert-To-UnixLineEndings $ResolvConfFile\n\nPause "Press any key to continue..."\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n


Mor*_*ten 5

编辑resolv.conf为仅包含 Cisco Anyconnect VPN NIC 提供的 DNS 服务器:

nameserver X.X.X.X
nameserver X.X.X.X
Run Code Online (Sandbox Code Playgroud)

现在,WSL 中的 DNS 在连接到 VPN 和断开连接时都能完美运行。
这超出了我的想象,但显然它与 Cisco Anyconnect VPN 和(分割)DNS 有关。