前言
此方法已经过气,请参阅 WSL2 2.0 更新。
网上为 WSL2 配置静态 IP 的方案有非常多,其中比较方便的一是其自带的桥接,二是这里的提前创建网络法。
然而,桥接实在是不太适合外部网络经常变化的环境(比如笔记本),而提前创建网络的方法则显得有些太过于 hacky 了:ICS 仿佛是 Windows 不愿暴露在外的“隐藏功能”,而且我也完全不知道他那网络的 GUID 是哪里来的,会不会存在向后兼容的问题。
所以,有没有什么相对“正常”一点的方法,能够为 WSL2 创建一个类似 VMware NAT 模式的网络,既做到固定网段,又做到不受外部网络环境影响呢?
这篇文章研究的就是这个问题。
步骤
先说步骤,最后再慢慢解释。
首先,打开设备管理器,选中你的电脑名,点击上方的操作,选择“添加过时硬件”:
选择手动安装:
选择网络适配器:
厂商选择 Microsoft ,找到其下的“Microsoft KM-TEST 环回适配器”:
完成后,你应该就可以在“网络连接”中看到它了,可以随便改个名字啥的(无所谓):
接下来,打开 Hyper-V 的虚拟交换机管理器,创建一个外部网络,将其桥接到刚刚创建的环回适配器上:
完成上一步后,“网络连接”中应该会出现一个新的名为“vEthernet(<你的外部网络名>)”的网络适配器,点开它的属性,为它设置一个 IPv4 地址,这个地址就是以后的宿主机 IP 了:
接下来,需要下载 DHCP Server ,这是一个不需要安装(甚至不需要管理员权限)的 portable 软件。这个软件分为两个部分,一个是 dhcpwiz.exe
用于创建配置文件,另一个是 dhcpsrv.exe
用于提供 DHCP 服务。将下载的压缩包解压到某个位置后双击 dhcpwiz.exe
启动“配置器”。启动后,选择刚刚创建的外部网络,点击下一页:
这一页无需配置,可以直接跳过:
在这一页中,你可以配置 IP 池、租期等信息,别忘了点开 Advanced ,并在其中配置 DNS 和网关地址,网关地址需要被配置为宿主机 IP,同样的, IP 池也得和宿主机 IP 在同一网段 :
↑ 对于上面这一步,如果你只是想要固定 IP 段,像我这样配置即可。但是如果你想要固定 WSL2 的 IP 地址,那么需要将 IP 池进行收缩,收缩到只有一个地址时,WSL2 的 IP 也就固定下来了 xD。
在这一页中,将对刚刚设置的内容进行保存。如果你之前没有配置过,直接点击 Write INI file
即可,如果之前配置过,则需要勾选 Overwrite existing file
来确保配置能够成功覆盖:
接下来这一页,因为我不想给管理员权限,于是什么都不干,直接点击完成:
↑ 至于开机启动,接下来自有办法。
那么配置过程就到此结束了,接下来点开 dhcpsrv.exe
来在我们的网络上启动 DHCP:
↑ 勾选 Don't show this window next time
,然后点击 Continue as tray app
让其最小化到托盘,此时 DHCP 服务已经在后台默默运行了。
接下来我们在不给管理员权限、不安装服务的前提下,为它配置一个超干净的开机启动。打开“运行”,输入 shell:startup
,此时资源管理器会弹出 “启动” 窗口,我们只需要在其中为 dhcpsrv.exe
创建一个快捷方式即可。
此时,网络本身算是配置好了,那就打开 .wslconfig
把 WSL2 接入进去吧:
C:\Users\<用户名>\.wslconfig
[wsl2]
networkingMode=bridged
vmSwitch=vNAT #这个要对应到上面在 Hyper-V 中创建的外部网络名称
好了,现在 wsl --shutdown
然后重新打开 WSL2 ,看一看自己的 IP 地址,诶,是不是在目标网段了?甚至还就是右下角弹出的 DHCP Server 分配的那个:
现在,宿主机和 WSL2 之间已经可以正常通信了,但是,WSL2 还不能访问外网,这是因为现在的网关是宿主机,而宿主机却并没有转发这些数据包的能力。
接下来,我们要为宿主机配置这种能力,上 NAT !
这一步,很遗憾的,我没有找到可以用的 GUI ,只能上 Powershell 了,记得给管理员权限:
New-NetNat -Name NAT -InternalIPInterfaceAddressPrefix 192.168.114.0/24
这里指定的内部网段要与上面分配的网段相对应。
好了,现在在 WSL2 中 ping
一下,网已经通了:
如果它没有通,那么你就得检查一下防火墙了,比如我用的卡巴斯基就得把这个虚拟网络设置为“本地网络”或者“受信任网络”才能正常使用 NAT 。
完成了,我们得到了一个类似 VMware NAT 模式的 WSL2 网络。
解释
接下来,解释一下这个过程,以及我为什么这么做。
首先的首先,最根本的原因,WSL2 是基于 Hyper-V 的,而 Hyper-V 压根就不支持创建 NAT 模式的网络。嗯,它自带的 Default Switch 是一个 NAT 模式的,甚至自带 DHCP 的网络,为 WSL2 自动创建的名为 WSL 的网络也是如此。但,它们都是基于 ICS 服务的,在开机时/开机后首次打开 WSL2 时会被重新创建,因而地址全都在乱跳。ICS 几乎没有什么比较正常的手动配置方法,或者说,微软似乎很不情愿让你感知到它们的存在,它们不仅不在任务管理器中显示,也不在“网络连接”中显示,但它们确确实实是网络😂。文章“前言”中提到的那种直接调用 api 的方式算是一种非常 hacky 的 ICS 配置方法,由于没什么文档,我也没法在此处深入探究了。
嗯,Windows 既有 NAT 功能又有 DHCP 功能,但就是不让你用,气不气?
按照上面我们的搭建方式,其得到网络的拓扑结构是这样的:
↑ 图中的命名就按上文中的来。
我们最开始创建的回环网卡,被 Hyper-V 的“外部网络”交换机一分为二,分别连接到了宿主机和 WSL2 中,这是通信的物理基础。你可能会问,为什么我不直接创建一个“内部网络”,这样不也可以得到一对相互连接的虚拟网卡吗?是的,对于一般的 Hyper-V 虚拟机,这样确实是可以的。但是,WSL2 的 networkingMode=bridged
只支持类型为“外部网络”的网络,“内部网络”压根就接不进去🤣。所以,这算是一种迫不得已的 workaround 。不得不说,微软在优雅的地方真的能做到非常优雅,但是这种屑的地方又能做到非常蛋疼。
这样建立的网络仅仅只是在数据链路层完成了配置,网络层的配置并没有完成。此时其实在 WSL2 中手动配置一个同网段的 IP 地址是能够通信的,但是对于 WSL2 这种东西来说,从外部配置远比从内部配置来的简单和稳定,这便是为什么需要搭建一个 DHCP 服务让 WSL2 能够自动获取 IP 地址,或者说,我只是在复现 ICS 自带的功能罢了。Windows 完全是自带了 DHCP 服务能力的,比如 ICS 自身具备的那个,又或者 Windows Server 系统中提供的那个,但,对于我们这些普通用户,微软就是不让你用,气不气?又是一次迫不得已,选择了 DHCP Server 。
接下来说一说 NAT ,这个东西的文档是在这里找到的,我取了其中创建 NAT 的一行命令,因为这个东西是真的找不到 GUI 。另外,这个 NAT 是不支持 IPv6 的(微软:怎么样就问你服不服?)。
问题
首先是 IPv6 ,上面也说到了,New-NetNat
创建的 NAT 不支持 IPv6 ,我们使用的 DHCP Server 也不支持 DHCPv6 。
其次,假如宿主机采用的是拨号上网,那么我们这样创建的网络是无法正常连接外网的,表现为 ping
都正常,但是 https 全部 insecure ,tls 握手直接爆炸。这并不是我们的配置哪里有问题,而是 Hyper-V 的 bug ,不信你试试 Hyper-V 自带的 Default Switch ,在拨号上网环境下也是这个鸟样。真有你的啊微软。
↑ 但是 WSL2 自动创建的那个名为 WSL 的网络并没有这个问题,可能是修复了但又没有完全修复(翻了翻 issue 发现以前好像也有这个问题,但好像被修复了,那为什么普通的 Hyper-V 就没修???)。
后记
由于拨号上网是刚需,这篇文章中的经验对我来说已经是答辩了。如果它能对你有所帮助,那我的努力也算没有白费🤣。
照着配置了,可以,感谢!
请教一下,如果wsl2上安装了多个发行版的情况下,每个发行版启动时获取的ip是不同的,还是说有可能会冲突
https://superuser.com/questions/1715273/wsl2-two-separate-centos-distributions-have-same-eth0-inet-address
按照这里的说法,多个 WSL 发行版实际上是以类似容器的方式共存的,它们共享同一个内核,同一个 network namespace ,因此它们的 ip 地址是相同的。
还是没有解决掉本质问题啊!wsl 固定ip是一桥接的一码事,但是更关键的是提供外部服务,说白了就是有个独立的外部IP可以给其他人直接访问,所以真正理想的模型的,是wsl 双网卡,一个网卡是使用windows NAT 固定ip(甚至不需要DHCP服务),另一个网卡桥接外部网络,这样宿主机通过nat固定ip可以访问wsl,笔记本接入新的环境做开发时,只要告知别人新的外部ip就可以提供服务。。。
微软是真的。。。。考虑下hyper-v 的开发环境难道不都是这么玩的吗?照抄都不会。。。现在wsl开发还不如直接hyper-v