OpenVPN 中的路由应该放在哪里:客户端还是服务端
在服务端配置里写一条裸路由,改的是服务端而不是客户端。选择客户端文件、全局 push 或单客户端 push,并确认到底有没有送达。
你把 route 10.60.0.0 255.255.255.0 加进服务端配置,重启,重新连接笔记本,可那个子网从这台笔记本依旧无法访问。这行配置被接受了,服务启动得很干净,日志里也看不出任何问题。实际情况是:路由装在了你编辑的那台机器上——网关现在以为自己能到达那个前缀,而客户端从未被告知任何事。位置就是全部问题所在,同一行配置可以住在四个地方。
四个位置以及各自由谁接收
路由可以由客户端自己的配置添加,可以通过全局 push 提供给每个客户端,可以通过客户端专属文件提供给某一个客户端,也可以写进服务端自己的路由上下文。
这四种情况使用的语法几乎一样,结果却完全不同。前三种影响的是客户端往隧道里发送什么;第四种影响的是服务端如何到达某个网络,它在服务端自己需要一条路径时有用,被误当成分发手段时则有害。
写这行之前,先确定你要的是四种里的哪一种,然后确认接收方。
| Placement | Effect | Receiver |
|---|---|---|
| Client profile route | Installed by the client at connect | That client only |
Global push "route ..." | Sent to every client that accepts pushed options | All pulling clients |
| Client-specific push | Sent to the matching client context | One identity |
| Server config route, no push | Added to the server's own table | The gateway itself |
为什么服务端里的裸路由让人意外
管理员最先看的往往是服务端配置,而那里的一条路由指令读起来像是关于 VPN 网络的声明。其实不是。OpenVPN 把它当作在运行守护进程的机器上做本地路由安装,这与你用 ip route 做一次改动然后忘掉,是同一种性质的事。
分发要求路由被 push,而 push 要求客户端去拉取。被禁用拉取选项后启动的客户端会完全忽略这项提供。在重写服务端文件之前,先检查这次握手的两端,因为服务端日志不会抱怨:从它那一侧看,提供已经发出。被接受的路由也只在下次连接时生效,绝不会落在你当前已经建立的会话里。
一旦把两件事分开看,故障就不再神秘:服务端能到达那个前缀,客户端不能,两句话同时成立。
每客户端文件以及它们匹配的身份
客户端专属文件以服务端通过认证的身份命名,默认就是证书的通用名称。桌面客户端里好听的连接名并不是那个值,对不上就会产生一个永远不会被读取的文件。
先查清服务端实际使用的目录,再确认文件名与已认证身份完全一致,包括大小写。
grep -n 'client-config-dir' /etc/openvpn/server/server.conf
ls -l /etc/openvpn/ccd/在该文件内部,路由仍然必须被 push,因为单客户端上下文是施加到该客户端会话上的一组选项,而不是本地路由表。那里写裸路由,和全局文件里写裸路由是同一个问题。
客户端自己的文件与掌管它的工具
放在客户端配置里的路由会在该客户端连接时安装、断开时移除,这对静态目标而言是正确的生命周期。
如果配置文件由网络管理器掌管,它可能只导入一次这些选项,然后保留自己的一份副本。之后再改下载来的文件不会改变任何东西,这正是「路由明明在,却不生效」的常见原因。
查当前生效的配置文件,而不是你下载下来的那个文件,并检查管理器显示的已导入设置。然后连接,问系统某个具体地址走的是哪条路径,而不是因为文本文件里写着路由就假定隧道赢了。
先在客户端验证,再检查回程
去问客户端自己的路由表目标地址怎么走,而不是问服务端的。查前缀里的单台主机就足以显示将被使用的接口和下一跳。
ip route get 10.60.0.10如果查询指向隧道,说明分发成功了,剩下的问题在别处。如果它指向默认网关,那么路由没有安装、被客户端侧的选项过滤掉了,或者属于客户端并未使用的配置文件。
假定分发成功,却依然没有回应:那就检查网关上的转发、对端的回程路由,以及两者之间的任何防火墙。路由只选择路径,不授予访问权限。