如果你在 Windows 上装了 WSL2,同时又装了某个会在系统里创建 TUN 虚拟网卡的组网工具,你多半遇到过这种困惑:Windows 侧一切正常,那个 TUN 网卡也能正常工作,但 WSL 里要么连不上外网,要么流量根本就不走 TUN 那一路。我最近正好折腾完这个事,把 WSL 的网络流量成功引导到了 Windows 侧的 TUN 虚拟网卡上。这篇文章就把整个思路、操作步骤和踩坑过程写清楚,所有操作都基于 WSL2 和 Windows 10/11 实测,不绑定具体软件,凡是能创建 TUN 设备的方案都能套用。
1. 为什么 WSL2 默认连不上"Windows 侧那一路网络",问题到底出在哪
先说结论:WSL1 和 WSL2 的网络架构完全不同,你如果在 WSL1 里压根没遇到这个问题,那到了 WSL2 大概率就会遇到。搞清楚这个底层差异,后面所有操作才有意义。
1.1 WSL1 和 WSL2 的网络栈差异
WSL1 不是一个虚拟机,它通过 Windows 内核提供的系统调用翻译层,直接跑在 Windows 的进程模型里。这意味着 WSL1 里的网络请求本质上就是 Windows 进程的网络请求,直接复用 Windows 的 IP 栈、路由表和 DNS 配置。你 Windows 能访问什么,WSL1 就能访问什么,TUN 虚拟网卡创建的路由对它天然生效。
WSL2 则完全是另一回事。它跑在 Hyper-V 虚拟化平台上,是一个轻量级虚拟机,里面有一个独立的 Linux 内核。这个虚拟机通过一个虚拟交换机(vEthernet (WSL))和 Windows 通信,Windows 给 WSL2 分配的是一个 NAT 网络。你在 WSL2 里执行 ip addr 看到的 eth0,拿到的 IP 通常是 172.x.x.x 或 192.168.x.x,和 Windows 宿主机不在同一个网段,而是躲在 NAT 后面。
问题就出在这里。TUN 虚拟网卡是创建在 Windows 宿主机内核里的三层虚拟网络设备,它的路由规则写在 Windows 的路由表里。WSL2 的流量从虚拟机出来以后,直接经过 Hyper-V 虚拟交换机和 NAT 转发,通常到不了 Windows 主机的路由决策层,自然也就不会进入 TUN 网卡。
你可以在 WSL2 里执行下面这条命令看看当前网络结构:
bash复制ip addr show eth0
ip route show
正常你会看到类似这样的输出:
text复制inet 172.20.16.2/20 brd 172.20.31.255 scope global eth0
default via 172.20.16.1 dev eth0
这个 172.20.16.1 就是 Windows 侧 vEthernet (WSL) 接口的 IP。WSL2 里所有出网流量先发给这个网关,再由 Hyper-V NAT 转发到物理网卡。而 TUN 网卡挂在 Windows 主机的另一侧,流量根本没被路由到那里。
1.2 使用场景:什么时候必须让 WSL 走 TUN 虚拟网卡
TUN 虚拟网卡最常见的用途,是某类组网软件在系统里创建一个虚拟三层接口,把发往某个网段的数据包交给该软件进程去封装和处理,再通过现有的物理网络发送到远端。比如公司远程办公接入后,你可能会在 Windows 里看到一个 TUN 网卡,它的地址是 10.10.0.2/16,Windows 路由表里多了 10.10.0.0/16 via 10.10.0.1 这样的条目。
此时如果 WSL2 里跑着一些服务或脚本,需要访问这个远端网络的资源(公司内网数据库、NAS、内部服务等),你会发现 Windows 能通,但 WSL2 里 ping 不通。原因就是我前面说的那条:WSL2 的流量没有经过 Windows 路由表,也就没有进入 TUN 设备的处理链。
另外还有一种场景:你把某个测试服务跑在 WSL2 里,希望它通过 Windows 侧访问某个特定网络出口。虽然可以用端口转发硬凑,但如果有多个端口、多个服务,就需要一个更全局的连通方案。
1.3 我踩过的坑:默认 NAT 模式下 WSL2 的 IP 被"藏"起来了
刚开始我以为是 DNS 问题,在 WSL2 里手动改了 /etc/resolv.conf,指向 Windows 宿主的 DNS,发现没用。后来在 Windows 侧抓包,才发现 WSL2 发出的包在 Hyper-V NAT 那一层就被改写了源地址,变成了 172.20.16.x 网段的地址,甚至你根本看不到它原本的目的地。这说明流量压根没有进入 Windows 主机的路由查找流程,更不用说触发 TUN 网卡了。
这也解释了为什么你在 WSL2 里设置"静态路由"往往是无效的,因为默认 NAT 模式下,WSL2 内部的 eth0 接口绑定的就是 Hyper-V 虚拟交换机分配的地址,你只能在这个虚拟交换机范围内活动。想让流量真正接入 TUN 网卡,要么让 WSL2 直接复用 Windows 的网络栈,要么手工搭建一条从 WSL2 到 TUN 网卡的转发链路。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前的网卡体检:确认 TUN 设备与现有路由的真实状态
在写任何配置之前,先把 Windows 和 WSL2 两侧的网络状态全部摸清楚。这一步容易被人跳过,结果改了半天路由、发现 TUN 网卡名写错了。
2.1 查看 Windows 网卡列表与 TUN 设备
打开管理员 PowerShell,执行:
powershell复制Get-NetAdapter | Format-Table Name, InterfaceDescription, Status, ifIndex
你会看到类似这样的输出:
text复制Name InterfaceDescription Status ifIndex
---- ------------------------ ------ -------
vEthernet (WSL (hyper-v)) Hyper-V Virtual Ethernet Adapter Up 12
TUN TAP-Windows Adapter V9 Up 18
以太网 Realtek PCIe GbE Family Controller Up 5
注意 TUN 设备的 InterfaceDescription 可能会有后缀 "Win32",但关键是 Status 必须是 Up。如果它显示 Disabled 或 Disconnected,说明组网软件没有正常启动,或驱动没有正确加载。
然后查看 TUN 网卡的 IP 地址和它对应的路由条目:
powershell复制Get-NetIPAddress -InterfaceAlias "TUN"
Get-NetRoute -InterfaceAlias "TUN"
把得到的 IP 网段和路由网段记录下来,后面配置会用到。
2.2 读懂 route print:默认路由、接口 metric 与跃点
再用管理员命令行执行 route print(或 PowerShell 里 Get-NetRoute),重点看两个东西:
Active Routes里,TUN 网卡对应的网段是走哪条路由。- Windows 的默认路由最终指向哪个接口。
很多人一上来就把 WSL 的默认路由改成 TUN 网卡,结果把 WSL 访问 Windows 内网也给断了,因为 TUN 网卡所在网段和 vEthernet (WSL) 不在一个子网。我建议先只专注于"哪些目标网段需要走 TUN",把这些网段的路由记下来:
text复制10.10.0.0 255.255.0.0 10.10.0.1 10.10.0.2 TUN
这里的 10.10.0.2 是 TUN 网卡接口的 IP,10.10.0.1 是它所在链路的网关。后面手工转发方案里,这个条目的信息会派上大用场。
2.3 先用 ping 确认 WSL2 现有的出网链路
在 WSL2 里执行:
bash复制ping -c 3 172.20.16.1
ping -c 3 223.5.5.5
第一条是测 WSL 到 Windows vEthernet 网关的连通性,第二条是测公网。如果公网能通,说明 Hyper-V NAT 链路正常,问题只在于流量没走 TUN。这一步验证能帮你排除一些低级问题,比如 WSL2 本身没网、DNS 配置被破坏等。
做完这些,你就有了三份关键信息:TUN 网卡名称、TUN 网卡绑定的网段、WSL2 eth0 的网关 IP。下面可以正式选方案了。
3. 方案一:打开 WSL 的镜像网络模式,直接复用 Windows 网络栈
这是最省事、最推荐优先尝试的方案,前提是你的 Windows 版本支持。
3.1 什么是镜像网络模式,为什么它能解决"TUN 看不到 WSL 流量"
从 WSL 2.0.0 开始,Windows 11 22H2 及以上版本支持一种叫 mirrored 的网络模式。它的原理是把 Windows 宿主机上的网络接口和路由表以镜像方式暴露给 WSL2,WSL2 内的网络栈与 Windows 的 IP 栈高度共享。你可以简单理解为:WSL2 不再是躲在 NAT 后面的一台"独立小电脑",而是跟 Windows 用同一套网络地址和路由规则。
这意味着,Windows 路由表里凡是经过 TUN 网卡的路由条目,在 WSL2 里也会出现。你在 WSL2 里访问 10.10.0.0/16 的资源,流量会直接挑中那条指向 TUN 网卡的路由,无需任何额外手工配置。
这是目前体验最接近"一体化"的方案,也是我最后留用的方案。
3.2 配置步骤:.wslconfig 与 wsl --shutdown
先在 Windows 用户目录下(一般是 C:\Users\你的用户名)创建或编辑 .wslconfig 文件,内容如下:
ini复制[wsl2]
networkingMode=mirrored
有些版本的 Windows 还需要同时开启下面两个选项,才能让 DNS 和网络发现在镜像模式下正常运作:
ini复制[wsl2]
networkingMode=mirrored
dnsTunneling=true
firewall=true
保存后,管理员 PowerShell 执行:
powershell复制wsl --shutdown
然后重新进入 WSL2。执行:
bash复制ip addr show
ip route show
你会看到 eth0 的地址已经和 Windows 主机的 IP 一致,路由表里也出现了 TUN 网卡对应的网段路由。此时直接 ping 一下远端网络地址,如果通了,大功告成。
3.3 镜像模式生效后的验证与边界
验证通过后,我建议多做一步确认:在 WSL2 里用 traceroute 看一跳到目标地址的路径。如果第一跳就是 Windows 侧 TUN 网卡的网关 IP,说明流量确实走了 TUN。
镜像模式也有它的边界。第一,它要求 Windows 版本不能太旧,Win10 用户基本无缘;第二,开启了镜像模式后,WSL2 里看到的接口变多,防火墙策略也跟着复杂起来;第三,如果你同时运行 Docker Desktop 等依赖自定义网络的中型容器工具,可能出现接口名冲突。这些事遇到再排查,但方案框架足够可靠。
4. 方案二:手工搭建"WSL → Windows 侧 TUN 网卡"的转发链路
如果你用的是 Win10,或者因为某些原因不能开镜像模式,那就走手工转发方案。这个方案虽然步骤多一些,但胜在通用,任何 WSL2 版本都能用。
4.1 核心思路:把 TUN 网卡当作上游网关
手工方案的本质是:WSL2 里的流量先发给 Windows 的 vEthernet (WSL) 网关,Windows 收到后再按自己的路由表决定是否转发到 TUN 网卡。要做的工作有三件:
- 开启 Windows 对 vEthernet (WSL) 接口的 IP 转发。
- 在 WSL2 里添加去往目标网段的路由,下一跳指向 Windows 侧 vEthernet (WSL) 的 IP。
- 放行 Windows 防火墙对 vEthernet (WSL) 接口的流量。
4.2 配置步骤:新增路由、启用 IP 转发、调整防火墙
先在 WSL2 里查一下网关 IP:
bash复制ip route show | grep default
假设输出是:
text复制default via 172.20.16.1 dev eth0
记下 172.20.16.1。然后在管理员 PowerShell 里启用这个接口的转发:
powershell复制Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" | Set-NetIPInterface -Forwarding Enabled
接着在 WSL2 里添加去往目标网段的路由。假设远端网络是 10.10.0.0/16:
bash复制sudo ip route add 10.10.0.0/16 via 172.20.16.1 dev eth0
这条命令的含义是:凡是目标地址在 10.10.0.0/16 范围内的包,全部先交给 172.20.16.1(也就是 Windows 的 vEthernet 接口),由 Windows 做二次路由决策。Windows 收到这些包后,如果它的路由表里存在 10.10.0.0/16 via 10.10.0.1 dev TUN 这条路由,就会继续转发到 TUN 网卡。
接下来处理防火墙。Hyper-V 的虚拟交换机默认不会放行来自虚拟机的跨网段转发流量,所以需要新增一条入站规则:
powershell复制New-NetFirewallRule -DisplayName "WSL2 TUN Forward" -Direction Inbound -InterfaceAlias "vEthernet (WSL)" -Action Allow
如果你担心影响面,可以把这条规则的协议和端口限定得更严格。比如只允许 TCP 流量通过,或者只放行特定端口。
4.3 验证流量是否真正经过 TUN 网卡
配置完后,在 WSL2 里执行:
bash复制ping -c 4 10.10.0.5
如果通了,说明链路已经打通。如果想确认包确实走了 TUN 网卡,可以在 Windows 侧用 netsh trace 抓包,或者在 TUN 网卡上挂一个计数器。更简单的验证方式:在 WSL2 里 traceroute -n 10.10.0.5,如果第一跳是 172.20.16.1,第二跳是 10.10.0.1,基本可以确认转发链路正常。
4.4 遇到 DNS 解析失败的排查链路
链路通了但域名解析不了,是这套方案里最常见的后续问题。原因很好猜:WSL2 默认使用的 DNS 是 Windows 在 NAT 网络里分配的 DNS 地址,而目标网络的 DNS 服务器在 TUN 网卡的另一侧,WSL2 的 DNS 请求可能根本没有发给正确的位置。
解决思路是让 WSL2 的 DNS 走 Windows 网关,由 Windows 做 DNS 解析后返回结果。在 WSL2 里编辑 /etc/resolv.conf,把 nameserver 指向 Windows 侧 vEthernet (WSL) 的 IP 172.20.16.1。但有个坑:WSL2 每次启动会根据 /etc/wsl.conf 自动重新生成 /etc/resolv.conf,你手工改完重启后就白改了。需要在 /etc/wsl.conf 里加一句:
ini复制[network]
generateResolvConf = false
保存后重启 WSL2,再手动写 /etc/resolv.conf:
text复制nameserver 172.20.16.1
如果你希望用 TUN 网络自带的 DNS(比如 10.10.0.1),也可以直接写它,前提是 WSL2 到 10.10.0.1 的路由已经加好了。实测下来,把 DNS 放到 Windows 宿主机通常更稳,因为 Windows 能同时处理多套网络的 DNS 解析逻辑。
5. 方案三:使用 netsh portproxy 做端口级转发(当只服务个别端口时)
有些场景不需要整个网段都通,你只是想从 WSL2 访问远端网络上的某一个固定服务,比如内网 10.10.0.5 的 443 端口,那就不值得改路由、开转发,直接上端口转发更快。
5.1 什么场景适合端口转发
端口转发适合"服务数量少、端口固定"的场景。例如你在 WSL2 里跑一个脚本,需要定时从公司内网的某个 API 拉数据,这个 API 只暴露了一个 443 端口,目标 IP 也恒定。此时用 netsh interface portproxy 映射一下,WSL2 里根本不需要改任何路由,直接访问 Windows 宿主机的某个端口即可。
还有一个典型场景:WSL2 里跑着 Web 服务,需要被 TUN 网络另一侧的用户访问,这时反向映射也有用。不过这类需求通常用 Windows 端口转发也能凑合,看你的网络拓扑。
5.2 配置命令与注意点
管理员 PowerShell 执行:
powershell复制netsh interface portproxy add v4tov4 listenport=9000 listenaddress=0.0.0.0 connectport=443 connectaddress=10.10.0.5
这条命令的含义是:Windows 监听本机所有网卡的 9000 端口,收到请求后转发给 10.10.0.5 的 443 端口。注意 listenaddress=0.0.0.0 意味着所有来源的流量都接受,包括 WSL2 通过 vEthernet 网卡发来的请求。所以 WSL2 里只需要访问 172.20.16.1:9000 或者 Windows 宿主机的实际 IP:9000 就行。
但 portproxy 默认不通过 Windows 防火墙的入站规则,所以还要加一条:
powershell复制netsh advfirewall firewall add rule name="WSL2-portproxy-9000" dir=in action=allow protocol=TCP localport=9000
验证就是把 WSL2 关掉再重启,然后用 curl 或 Test-NetConnection 测一下:
bash复制curl -k https://172.20.16.1:9000
| 对比项 | 手工路由转发 | 端口转发 |
|---|---|---|
| 适用范围 | 整个网段/多个服务 | 单个端口/固定服务 |
| 配置复杂度 | 中高,涉及路由和防火墙 | 低,两条命令搞定 |
| WSL2 路由表改动 | 需要添加路由 | 不需要 |
| DNS 需求 | 需要额外处理 | 不需要,Windows 侧完成 |
| 典型场景 | 内网多服务访问 | 固定 API、固定服务端口 |
5.3 与前面方案对比,如何选择
我个人的选择顺序是这样的:能开镜像模式就直接开,最省心;不能开镜像模式,但需要访问整个内网网段,就手工转发;如果只是零星一两个服务,直接 portproxy。这三个方案不是互斥的,甚至可以混用。你完全可以让镜像模式兜底,同时保留几个 portproxy 规则,以备特殊需求。
6. 实测中的常见异常与修复经验
方案写完了,但实际部署时大概率还会碰到一些幺蛾子。我把踩过的问题整理成清单,每一条都附上排查思路。
6.1 WSL2 每次重启后手工路由丢失
手工添加的 ip route add 是临时的,WSL2 每次冷启动都会重建网络栈,路由表恢复原状。很无语,但这是虚拟网卡的动态特性。
解决方式有三种。一是改用 networkingMode=mirrored,彻底告别手工路由。二是在 WSL2 内部写一个启动脚本,用 systemd 或启动 profile 自动执行 ip route add。三是写一个 Windows 批处理脚本,每次启动后调用:
powershell复制wsl -d Ubuntu -u root -- ip route add 10.10.0.0/16 via 172.20.16.1 dev eth0
第三种方式不依赖 WSL2 内部配置,适合在 Windows 侧统一管理。我个人更喜欢第二种,因为路由逻辑和服务一起走,不会暴露到 Windows 侧。
6.2 TUN 网卡 IP 段与 WSL NAT 网段冲突
这是隐蔽的坑。WSL2 默认 NAT 网段有时候是 172.20.16.0/20,而某些组网工具给 TUN 网卡分配的也是 172.20.x.x。两边都在同一个 172.20.0.0/16 大段里,路由直接互相踩脚。
排查方法:在 Windows 侧执行 route print,如果看到两条目标网段极度相近、但 interface 不同的路由,就要小心了。解决办法是给 WSL2 换一个子网。在 .wslconfig 里指定:
ini复制[wsl2]
subnet=192.168.81.0/24
ipAddress=192.168.81.2
然后 wsl --shutdown 重建。注意这个功能需要较新的 WSL 版本支持,老版本只认默认网段。
6.3 开启镜像网络模式后,TCP 通但 ICMP 不通
镜像模式下 WSL2 与 Windows 共享接口,理论上 ping 和 TCP 都该通。但我碰到过 ping 不通却能正常访问 HTTP 服务的情况,原因是 Windows 防火墙对来自本地接口的 ICMP 入站规则限制更严,而 TCP 规则被一些组网工具放行了。
排查思路:先确认目标服务本身能不能从 Windows 通,然后用 Test-NetConnection 测 TCP:
powershell复制Test-NetConnection 10.10.0.5 -Port 443
如果 TCP 通、ICMP 不通,大概率不是路由问题,而是防火墙策略。可以放行 ICMP 入站:
powershell复制netsh advfirewall firewall add rule name="allow icmp from wsl" protocol=icmpv4:any,any dir=in action=allow
6.4 DNS 解析时快时慢,经常超时
这是 TUN 网卡 + WSL2 最常见的组合问题。根源在于 DNS 流量没有和业务流量走同一条链路。有两种修复思路:优先尝试把 resolv.conf 指向 Windows 宿主机的网关地址;如果还不行,就直接指向 TUN 网络提供的 DNS 服务器地址。但注意,指向 TUN 网络 DNS 的前提是你已经加了对应网段的路由,否则 DNS 包发不出去。
我自己最后是采用了镜像网络模式 + dnsTunneling=true 的组合,DNS 解析一次搞定,再没出现过超时的问题。如果你不能升级到镜像模式,那就老老实实把 /etc/resolv.conf 写死,并关闭自动生成。
最后再分享一个容易被忽视的点:如果你系统里同时存在多个 TUN 网卡(有些组网工具会创建一块主 TUN 和一块辅助 TUN),一定要先确认你在操作的是哪一块网卡。判断标准很简单,看 Windows 路由表里对应网段条目的 ifIndex 或接口名,然后顺着 Get-NetAdapter 的输出找到对应设备。我曾经因为操作了错误的网卡,在防火墙规则上浪费了一个晚上。TUN 是三层接口,如果你遇到的是 TAP 二层设备(比如某些桥接场景),那本文的路由方案就不适用了,需要换成网桥方式,操作逻辑完全是另一套。
