本机 192.168.50.22 可以 ping 通 192.168.50.25,但 50.25 ping 不通本机。

两台机器明明在同一个 /24 网段里,问题却绕了一圈才显形:Clash TUN 改写了 macOS 路由,导致本机给 50.25 的 ICMP reply 没有直接发给 50.25,而是发给了网关 ImmortalWrt。

现象

网络环境:

1
2
3
4
本机:   192.168.50.22/24
对端: 192.168.50.25
网关: 192.168.50.2 ImmortalWrt
网卡: en0

本机地址看起来没问题:

1
ifconfig en0
1
2
inet 192.168.50.22 netmask 0xffffff00 broadcast 192.168.50.255
status: active

防火墙也不是主因:

1
2
Firewall is disabled. (State = 0)
Firewall stealth mode is off

真正反常的是路由。

第一处异常:同网段流量进了 TUN

查本机到 50.25 的路由:

1
route -n get 192.168.50.25

最初看到的是:

1
2
3
destination: 128.0.0.0
gateway: 198.18.0.1
interface: utun1024

192.168.50.25 是同网段地址,正常应该走 en0 直连,不应该进 utun1024

再看 Clash Verge / mihomo:

1
2
3
4
tun:
auto-route: true
device: utun1024
route-exclude-address: []

第一层原因很清楚:Clash TUN 的 auto-route 接管了不该接管的 LAN 路由。

第二处异常:排除 TUN 后仍然走网关

把 LAN 网段排除出去:

1
2
route-exclude-address:
- 192.168.50.0/24

此后 50.25 不再走 utun1024,但仍然不对:

1
2
3
destination: default
gateway: 192.168.50.2
interface: en0

这表示回包会从 en0 出去,但二层目标会是网关,而不是 50.25

同网段直连时,应该能 ARP 到对端:

1
arp -n 192.168.50.25

异常时却是:

1
192.168.50.25 -- no entry

到这里基本可以怀疑:本机缺少正常的 192.168.50.0/24 -> en0 直连路由。

关键证据:看二层 MAC

普通抓包只能说明本机收到了 request,也发出了 reply:

1
sudo tcpdump -ni en0 'icmp and host 192.168.50.25'
1
2
192.168.50.25 > 192.168.50.22: ICMP echo request
192.168.50.22 > 192.168.50.25: ICMP echo reply

但这还不够。它只说明三层 IP 是对的,没说明二层 MAC 发给了谁。

要看 MAC,加 -e

1
sudo tcpdump -eni en0 'icmp and host 192.168.50.25'

关键形态是:

1
2
1a:22:18:7f:6e:d5 > bc:24:11:78:02:22
192.168.50.22 > 192.168.50.25: ICMP echo reply

这里:

1
2
3
1a:22:18:7f:6e:d5   本机 50.22
bc:24:11:78:02:22 网关 50.2
30:f6:ef:9e:f4:df 对端 50.25

破案点就在这一行:

1
2
IP 目的地:  192.168.50.25
MAC 目的地: 192.168.50.2 的网关 MAC

也就是说,本机确实回包了,但回包在二层发错了人。

ImmortalWrt 只是佐证

在网关上也能看到同样的包:

1
tcpdump -eni eth0 'icmp and host 192.168.50.25 and host 192.168.50.22'
1
2
1a:22:18:7f:6e:d5 > bc:24:11:78:02:22
192.168.50.22 > 192.168.50.25: ICMP echo reply

网关知道 50.25 在同一个接口上:

1
ip route get 192.168.50.25 from 192.168.50.22 iif eth0
1
2
192.168.50.25 from 192.168.50.22 dev eth0
cache <redirect> iif eth0

但它只看到了 reply,没有看到对应的 request。对 conntrack 来说,这类包是 invalid,于是被 fw4 丢掉:

1
ct state invalid counter packets 44 bytes 2592 drop

所以不要去改网关防火墙兜底。真正该修的是本机路由。

根因

正常情况下,macOS 应该有这条直连路由:

1
192.168.50 link#12 UCSc en0

异常时,这条路由缺失或被 Clash TUN 的自动路由刷新打乱。结果是:

1
2
三层: 192.168.50.22 -> 192.168.50.25
二层: 本机 MAC -> 网关 MAC

看起来像“本机回了包”,实际是“包回错了二层目的地”。

修复

临时补回直连路由:

1
sudo route -n add -net 192.168.50.0 -netmask 255.255.255.0 -interface en0

验证:

1
2
route -n get 192.168.50.25
arp -n 192.168.50.25

期望看到:

1
2
interface: en0
192.168.50.25 at 30:f6:ef:9e:f4:df

长期保留 Clash TUN 排除项:

1
2
3
4
tun:
auto-route: true
route-exclude-address:
- 192.168.50.0/24

如果重启 Clash、切换 Wi-Fi 后又复现,继续检查 mihomo 的 auto-route 刷新行为;必要时关闭 auto-route,或写一个登录后自动补路由的小脚本。

以后怎么查

遇到“同网段单向 ping 不通”,不要只看 IP 层。按这个顺序查:

1
2
3
4
5
ifconfig en0
route -n get <peer-ip>
arp -n <peer-ip>
sudo tcpdump -ni en0 'icmp and host <peer-ip>'
sudo tcpdump -eni en0 'icmp and host <peer-ip>'

核心问题只有一个:

这个包在三层发给谁?在二层又发给谁?

这两个答案一旦不一致,根因通常就离你很近了。