VMware 偷走了我的 IPv4:一次纯靠 IPv6 完成的远程抢救
那天我远程启动了 Mac Studio 上的 VMware Fusion,然后这台机器就”消失”了。
ping 不通,VNC 连不上,SSH 也没有任何回应。而我人在外地,走过去按电源键这个选项并不存在。
最后的结局是:机器一秒都没有宕过,只是它的 IPv4 协议栈被 VMware 悄悄地掐断了。而 IPv6 完好无损——那就是那扇没上锁的后门。
先说结论
VMware Fusion 的某个 vmnet 虚拟网卡抢占了 192.168.50.0/24 这个网段,而这正是局域网真实使用的网段。于是 macOS 在做路由查找时,把所有发往 192.168.50.* 的回包——包括发给自己网关的回包——全都丢进了那块虚拟网卡,而不是 en0。
结果就是:包进得来,出不去。从外面看,这台机器像是彻底死了。
而 IPv6 使用带 scope 的路由(%接口),一个 IPv4 网段冲突根本碰不到它,VMware 的 vmnet 也不会去动 IPv6。所以这台机器的 IPv6 链路本地地址自始至终是通的。
修复方式:通过同网段的一台跳板机用 IPv6 SSH 进去,执行 vmnet-cli --stop。
排查过程
一、网络路径是好的,只有这台 Mac 是黑的
从我远程的机器(位于 10.10.10.0/24)测试:
| 目标 | 结果 |
|---|---|
192.168.50.254(网关) | ping 约 8ms,健康 |
192.168.50.48(Mac Studio) | 100% 丢包,22 / 5900 / 445 / 548 等所有端口全部静默 |
网关通、Mac 不通,说明到这个网段的路由和链路都没问题,故障被精确地圈定在这台 Mac 自己身上。
二、known_hosts 帮了大忙
翻了一下本地的 known_hosts:192.168.50.48 有 ed25519、rsa、ecdsa 三条记录,说明这台机器上 SSH 是开着的、而且我以前成功连上过。
更有用的是:同网段还有好几台机器也在 known_hosts 里(.20 .21 .30 .45 .88 .137)。这些都是现成的跳板机。
这是一个很容易被忽略的细节——known_hosts 本质上是一份”我曾经能连上的机器清单”,救急的时候它就是地图。
三、跳到同一个二层网段上去看
选了 192.168.50.137(一台 RHEL8,网卡 ens192,地址 192.168.50.137/24)。从它上面看:
ARP 查询 .48 -> ac:de:48:11:22:33 (Apple 的 OUI,不是 VMware 的)
arping .48 -> 约 0.9ms 有回应 (二层活着)
ping .48 (IPv4) -> 100% 丢包 (IPv4 回包路由坏了)
这三行信息量很大:
- arping 有回应 → 机器在二层是活的,网卡在工作,系统没死机。
- MAC 是 Apple 的 OUI → 排除了另一个高度可疑的原因:“某台桥接模式的虚拟机配了同样的静态 IP
.48,把地址抢走了”。如果是那样,ARP 回来的应该是 VMware 的 OUI(00:0c:29/00:50:56之类)。地址还在 Mac 自己手里,它只是回不了话。 - IPv4 ping 不通 → 问题就在 IPv4 的出向路由上。
四、IPv6 那边门是敞开的
Mac 的链路本地地址:fe80::1234:5678:9abc:def0
ping6 -> 0.47ms
SSH (tcp/22) -> SSH-2.0-OpenSSH_10.2
屏幕共享 (tcp/5900) -> RFB 003.889
到这里就完全确认了:机器健健康康,只有 IPv4 的路由被污染了。
根因
VMware Fusion 会给它的 vmnet1(host-only)和 vmnet8(NAT)半随机地分配 192.168.x.0/24 网段。这次它挑中(或者被配置成)了 192.168.50.0/24——和真实局域网撞了个正着。
于是这台 Mac 上有两块网卡同时宣称拥有同一个前缀,路由查找开始把 192.168.50.* 解析到 vmnet 而不是 en0。IPv4 全面静默,但系统其他一切正常。
这是个特别阴险的故障模式:它不会报错,不会写日志告警,只在你启动虚拟机的那一刻,安静地把这台机器从网上抹掉。
救援
入口:经跳板机,用 IPv6 链路本地地址 SSH
把 USER 换成 Mac 上的真实账号名:
ssh -J root@192.168.50.137 'USER@fe80::1234:5678:9abc:def0%ens192'
两个关键点:
%ens192是跳板机在该网段上的接口名。链路本地地址必须带 scope,因为fe80::/10在每块网卡上都有效,不指定接口内核不知道该往哪发。-J表示通过192.168.50.137做 ProxyJump。
进去之后:确认冲突,然后清掉
# 这里会看到某个 vmnet 接口也在认领 192.168.50.x:
netstat -rn -f inet | grep 192.168.50
# 停掉 VMware 的所有虚拟网络,IPv4 几秒内就会回来:
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --stop
# 再确认一次,现在应该只有 en0 认领这个网段:
netstat -rn -f inet | grep 192.168.50
如果不想把所有虚拟机都干掉,只想停掉那台闯祸的:
vmrun list
vmrun stop "/path/to/vm.vmx" soft
备选方案:不用 SSH,直接用 VNC
屏幕共享在 IPv6 上是通的,可以把它通过跳板机隧道出来,然后用 VNC 客户端连 localhost:5900:
ssh -L 5900:[fe80::1234:5678:9abc:def0%ens192]:5900 root@192.168.50.137
永久解决:把 VMware 挪出局域网网段
治标之后要治本,让它以后再也撞不上:
sudo vi "/Library/Preferences/VMware Fusion/networking"
# 把 VNET_8_HOSTONLY_SUBNET 192.168.50.0 改成 172.16.108.0
# (如果 VNET_1_ 也落在 192.168.50.0 上,一并改掉)
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --configure
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --start
下次怎么才能不这么狼狈
1. 给这台 Mac 装 Tailscale。
它跑在 utun 接口上,天然免疫 IPv4 前缀冲突。恰恰是这种故障模式下,它还是通的——连跳板机都不需要。
2. 把 VMware 的 vmnet 网段固定在你的局域网永远不会用的私有段,比如 172.16.x.0/24。
3. 记住 IPv6 这条逃生通道。 这是这次最大的收获:
# 在同网段任意一台机器上,枚举所有邻居:
ping6 ff02::1%<接口名>
# 即使目标主机的 IPv4 完全死透,带 scope 的 SSH 依然能进去:
ssh user@fe80::xxxx:xxxx:xxxx:xxxx%<接口名>
很多人把 IPv6 当成”以后才用得上的东西”顺手关掉了。这次它是唯一那条把机器救回来的路。双栈不是冗余,是保险。
速查表
Mac Studio IPv4 192.168.50.48
Mac Studio MAC ac:de:48:11:22:33 (Apple OUI)
Mac Studio IPv6 链路本地 fe80::1234:5678:9abc:def0
网关 192.168.50.254
跳板机 192.168.50.137 (RHEL8, ens192)