从 OpenVPN 无法访问子网到解决:一次 OpenWrt 路由排障记
✅ 先说答案:解决办法
- 去掉错误的静态路由:在 OpenWrt 的“静态路由”页面发现有一条
192.168.3.0/24指向网关192.168.3.254的路由(图 3)。这条规则会导致内核把去往192.168.3.1的包送到 WAN 口(pppoe-wan),从而无法通过 LAN2 到达目标。删除该路由,并重启网口后,内核自动生成的直连路由恢复正常。 - 恢复正确路由:确认
ip route get 192.168.3.1输出为dev eth2 src 192.168.3.254即可。此时 OpenWrt 本机可以正常 ping 通192.168.3.1,VPN 客户端也能访问。 - 若上级路由不知道 VPN 网络,则需要在上级路由(192.168.3.1)添加 回程路由(10.8.0.0/24 和 10.8.1.0/24 指向 192.168.3.254)。如果无法修改上级路由,可在 OpenWrt 的 VPN 区域开启 SNAT/MASQUERADE,让 VPN 客户端访问 LAN2 时使用
192.168.3.254作为源地址,从而绕过回程路由。SNAT 会在数据包离开内部网络时把源 IP 转换为网关的 IP,使外部主机看到的是转换后的地址.
下文按照时间顺序记录从发现问题、排查过程到最终解决的全过程。
📌 背景与网络拓扑
- OpenWrt 作为旁路由,LAN2 接口配置为
192.168.3.254/24,与主路由器(192.168.3.1)在同一网段,通过 eth2 物理接口连接。 - OpenVPN 服务器运行在 OpenWrt 上,通过 tun0/tun1 建立 10.8.0.0/24 与 10.8.1.0/24 两个虚拟子网。
- OpenVPN 的配置中已经正确
push "route 192.168.3.0 255.255.255.0"(图 1),客户端获得了访问 LAN2 网段的路由。 - 防火墙中定义了
VPN区域,并允许与lan区域互访,理论上 VPN 客户端可访问 192.168.3.0/24。
图 1 OpenVPN 服务器通过 push route 推送 192.168.3.0/24 到客户端
🔍 问题发现
VPN 客户端连接成功后,测试结果如下:
ping 192.168.3.254—— 可以通信,说明隧道连通、OpenWrt 可达。ping 192.168.3.1—— 完全丢包。同时在 OpenWrt 上直接ping 192.168.3.1也不通,初步排除回程路由问题,怀疑链路或本机路由。
🛠️ 排查过程(按时间顺序)
1. 确认配置无误
- 路由下发:打开 VPN 服务器配置,确认有
push "route 192.168.3.0 255.255.255.0"(图 1)。在客户端路由表中也看到了192.168.3.0/24走隧道,因此排除“未下发路由”。 - 防火墙:检查防火墙区域,
VPNzone 已经允许转发到lan区域;lan区域包含 LAN2 接口,因此防火墙不会阻止此流量。 - 二层连通性:使用
arping -I eth2 192.168.3.1,OpenWrt 能收到 192.168.3.1 的 ARP 回复,证明物理链路和交换网络正常。
图 2 防火墙中 VPN 区域允许与 lan 区域互访,且 LAN2 接口在 lan 区域
2. 发现内核路由错误
为了进一步定位原因,在 OpenWrt 上执行 ip route get 192.168.3.1,结果却是:
192.168.3.1 via 10.100.0.1 dev pppoe-wan src 10.100.18.64
也就是说,内核认为到 192.168.3.1 需要通过 WAN 口的上级网关,而不是直接走 LAN2 接口。这解释了为什么 ping 不通,因为包被送到外网去了。继续检查“静态路由”页面,发现一条异常的路由:
图 3 静态路由配置中把目的网段 192.168.3.0/24 的网关设成了本机 192.168.3.254,导致内核选路异常
这条路由的意思是 “到 192.168.3.0/24 要通过 192.168.3.254”,而 192.168.3.254 又是本机地址。由于优先级比自动生成的直连路由低,它没有立即生效,但在某些情况下会干扰内核的路由缓存,导致内核改走 WAN。这就是能 ping 通 192.168.3.254 却 ping 不通 192.168.3.1 的原因。
3. 临时修复验证
为了验证这一假设,先在命令行手动添加一条正确的直连路由:
ip route replace 192.168.3.0/24 dev eth2 scope link src 192.168.3.254
再执行 ip route get 192.168.3.1 得到:
192.168.3.1 dev eth2 src 192.168.3.254
这时 OpenWrt 本机 ping 192.168.3.1 就成功了,证明问题确实在路由表。随后删除上述错误的静态路由并重启网络服务,内核自动生成的直连路由(192.168.3.0/24 dev eth2) 恢复,问题解决。
4. VPN 客户端回程问题
经过上述操作,OpenWrt 本机与 192.168.3.1 可以互通。但 VPN 客户端 ping 192.168.3.1 时还是没有回应。使用 tcpdump -ni eth2 抓包发现,192.168.3.1 不停发送 who-has 10.8.0.2 的 ARP 请求。这说明它不知道 10.8.0.0/24 应该回到 192.168.3.254,而是误以为 10.8.0.2 就在本地以太网。
这就是经典的 回程路由缺失:上级路由(192.168.3.1)没有到 VPN 子网的路由,导致它无法把返回的流量交给 OpenWrt。
为了让 VPN 客户端能访问 192.168.3.0/24,有两个办法:
-
在 192.168.3.1 上配置静态路由:
10.8.0.0/24 via 192.168.3.25410.8.1.0/24 via 192.168.3.254
这样 192.168.3.1 就会把回包交给 OpenWrt,再通过 VPN 隧道转发给客户端。
-
在 OpenWrt 上开启 SNAT/MASQUERADE:
如果无法修改上级路由,可在防火墙的
VPN区域开启 IP 动态伪装(MASQUERADE)。当 VPN 客户端访问 192.168.3.0/24 时,OpenWrt 会把数据包的源地址从10.8.0.2修改为192.168.3.254,让 192.168.3.1 直接回复本机。SNAT 的定义是:当内部主机访问外部网络时,NAT 设备会将数据包的源 IP 地址从私有地址转换为公共地址,使外部主机看到的是转换后的地址【23302085190512†L146-L151】。由于回包只需要回到网关,不用知道真实源地址,SNAT 是一种“权宜之计”。
在我的环境中,上级路由并未禁止回程,于是在删除错误的静态路由后,OpenWrt 和上级路由之间的默认路由就能互通,因此不需要额外 NAT,VPN 客户端访问 192.168.3.1 也恢复正常。
🧾 总结与经验教训
- 不要在同一子网配置“指向自己”的静态路由。OpenWrt 已经为直连网段自动生成路由,额外添加错误的静态路由可能干扰内核路由选择,导致包走到意想不到的接口。
- 排查顺序很重要:
- 先验证 OpenVPN 是否正确推送路由和防火墙是否放行;
- 再用
arping和抓包确认二层链路; - 最关键是用
ip route get检查内核实际走哪条路径。
- 回程路由与 SNAT:如果上级路由不知道 VPN 子网的存在,就需要在上级路由添加回程路由;不能修改时,可以在 OpenWrt 对 VPN→LAN2 的流量做 SNAT,让源地址变成网关地址,利用 NAT 的源地址转换功能【23302085190512†L146-L151】。
- 工具与观察:
tcpdump、ip route get等工具在排查网络问题时非常有用,可以直观了解包的流向和路由决策。
这次排障经历虽然过程曲折,但充分说明了路由配置的重要性。通过系统的检查和逐步定位,最终找到了症结所在,也顺便复习了一遍 NAT 和回程路由的概念。

参与讨论
(Participate in the discussion)
参与讨论