客户端能 ping 通 OpenVPN 服务器的隧道地址并得到回应,接着去试服务器所在 LAN 的一台主机却毫无结果。这个分界把故障范围收得很窄:隧道是通的,转发大概率正常,而回包正从一扇不回到原处的门离开。修法有三种,选哪一种取决于你能控制什么、又愿意放弃什么。按顺序回答下面三个问题,选择就不再是口味问题。

先确认是哪个方向断了

请求带着来自 VPN 地址池的源地址到达隧道接口。服务器把它转发给 LAN 主机,那台主机则按自己路由表所指的网关回包,通常是 LAN 路由器。如果路由器没有通往地址池的路由,回包就在那里死掉,或者往互联网方向乱走。

动手改任何一台之前,先测两台机器。在服务器上查路由表会怎样到达某个客户端;在 LAN 主机上查它会怎样到达同一个地址。第一次查询通常指向隧道,第二次指向 LAN 路由器,这个差异就是一行字的故障。两次查询比一次防火墙审计便宜,而且能定下问题的方向。

ip route get 10.8.0.37
sysctl -n net.ipv4.ip_forward

如果 LAN 主机已经把回程指向 VPN 服务器,你的问题是防火墙规则或 MTU 上限,而不是缺少回程路由。不要为了修过滤器去加路由。

问题一:你能改远端 LAN 的路由器吗?

如果 LAN 路由器是你的,干净的答案是给 VPN 地址池加一条静态路由,下一跳用 VPN 服务器的 LAN 地址。它保留客户端源地址不变,这在 LAN 主机按地址做日志、过滤或限速时很重要。它也不需要服务器做任何地址转换,隧道因此仍是纯粹的路由路径。它带来的义务是文档:地址池、路由和服务器配置必须三处一致。

当有人改了地址池,它会在某天悄悄失效。把数值写下来一次,并把三处中任何一处的修改都当成三处一起改。

承载服务的 NAS 或 Layer 3 交换机也需要同一条路由,除非它把所有流量都交给一台已有该路由的路由器。要检查终结该子网的设备,而不只是朝向互联网的那台。小型网络里常常有三台设备都对路由各有看法。

问题二:LAN 能不再看到客户端地址吗?

当路由器属于别人时,在 VPN 服务器上做地址转换不需要对方配合。LAN 主机看到的是服务器的 LAN 地址,就回给它,服务器再转换回去。这就是设备和基于 NAT 的远程访问角色会这样表现的原因。

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

代价是可追溯性:每客户端地址从 LAN 日志里消失了。此时 LAN 主机上的任何白名单都必须写服务器地址,而不是地址池。

在无法取得配合时才选转换,而不是在仅仅不方便时。它会让客户端在所有后续排查中隐身,包括你必须知道是哪台笔记本发起的连接的那种排查。它还可能破坏把地址内嵌在载荷里的协议,因为转换只发生在报文头。两个选项没有高下之分;它们回答的是关于归属的两个不同问题。

问题三:服务器本身是不是另一条隧道的客户端?

换一种拓扑来想:VPN 服务器同时也拨号连到一家商业运营商,于是它有两条隧道、两套地址。它为自家客户端转发的流量从运营商出去,而运营商不会把回程路由回地址池。这就是两条隧道都健康、回包却消失的原因。

修法是给出去的那条隧道也做地址伪装,让运营商只看到服务器的隧道地址。反方向需要自己的规则,因为服务器主动连接自己的某个客户端是另一条流。没有那条规则,客户端会回给一个它无法路由的地址。把窄规则放在任何宽泛伪装之前,让具体的转换胜出。

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o tun1 -j MASQUERADE
iptables -t nat -A POSTROUTING -d 10.8.0.0/24 -o tun0 -j SNAT --to-source 10.8.0.1

多宿主主机还会带来一种从客户端看完全一样的相关故障。回包会从度量值更低的接口出去,因为源地址是从另一张表里选出来的。要用查询验证回程,而不能假定去程就蕴含回程。

然后两个方向、两种大小都要验

改完之后,先从客户端 ping LAN 主机,再从 LAN 主机 ping 客户端。第二个方向是大家会跳过的,也正是它暴露不完整的转换规则。把两个结果连时间戳一起记下来,日后出现回归才可对比。

然后传真实数据,因为小 ping 能通而大传输卡住是 MTU 的症状。这个故障往往出现在你刚为修好路由而自我表扬之后。

最后,重启之后再测一遍。运行时写下的路由和防火墙命令撑不过重启,而下一次开机就消失的修法会被一个上下文更少的人重新诊断。用你系统本来就有的方式把改动做成永久的,然后故意重启一次。

相关文章