Linux VPN 上,地址、路由、DNS 和防火墙归谁管?
Linux VPN 的每个对象只能有一个权威:设备、地址、路由、DNS、防火墙。先写下这张归属图,再定义启动、重连和拆卸各自恢复什么。
两个脚本争抢同一条路由,这是 Linux VPN 问题常见的形态,最后往往被登记成路由缺陷。一个组件创建隧道设备,另一个添加默认路由,第三个重写解析器配置,第四个重新加载防火墙规则。任何一个都能推翻另一个的成果,赢家只是最后执行的那个。真正值得回答的问题不是装哪个软件包,而是每一块状态由哪个组件负责。
把这张归属图写下来一次,大多数重连失败就不再神秘。关键对象有四个:设备及其地址、路由与策略规则、DNS 配置,以及防火墙。
设备及其地址
隧道设备要么由了解配置文件的管理器创建,要么由某人手动启动的守护进程创建。两种安排各自都能工作;混用则不行。如果配置文件归 NetworkManager 所有,就让设备也归它所有,不要针对同一个隧道名再启动一个不受管理的 OpenVPN 进程。
记录下来:会话结束时由谁删除设备。活得比会话更久的设备,是陈旧地址以及随之而来的混乱最常见的来源。
路由与策略规则
正是在路由上,归属冲突会造成看得见的破坏。连接管理器为隧道安装一条默认路由,再为远端网络安装一条更具体的路由;随后手写脚本用不同的度量值加上自己的默认路由,并随时机悄悄胜出或落败。要决定哪些条目属于连接级、哪些是永久策略、重连后由哪个组件刷新它们。然后让其他组件不要碰那张表。
策略规则也值得同样明确,因为指向无人填充的表的规则会制造一个黑洞,看起来和死掉的隧道一模一样。如果某条规则的存在是为了把流量逼向某处,那么它选中的表必须由同一个所有者维护。
DNS 永远是独立的所有者
解析器守护进程以自身身份作为独立进程运行,因此不会偶然继承隧道的路由决策。当 VPN 推送 DNS 服务器时,必须有东西把它翻译成解析器认可的按链路配置,之后还得有东西把它撤掉。
这里的误解是:把域名服务器写进配置文件会改变查询的去向。它改变的是告诉解析器什么,而不是解析器在上游使用哪个套接字。请用一次查询加一次路由查找来验证,而不是相信文件。
防火墙状态,以及由谁恢复它
防火墙规则是 VPN 主机上最常被覆盖的对象。管理器可能按连接添加 NAT 或转发规则,而启动时的防火墙服务会重新加载保存的规则集并把它们抹掉。为策略选定唯一的权威,让另一方成为它的消费者;或者接受重启会悄悄改变行为。属于连接级的例外应放在同一所有者加载的文件里,而不是排障时随手敲的 iptables 命令。
如果规则必须经受重连,就明确写出来。如果不必须,也要写出来,因为下一位工程师会假定更方便的那个答案。
生命周期:启动、重连、拆卸
给这三个时刻各指定一个所有者。启动时决定谁准备前置条件、按什么顺序。软重启时要记住设备可能存活,而会话状态不会,所以该跑的是校验器而不是创建器。拆卸时只移除这次连接创建的东西,因为重置所有路由或清空整个防火墙,并不等于退役一条隧道。
为了观察,ip monitor link address route 会在内核变化发生时显示它们,但它报告的是事件而不是意图:被删除的路由不会说明是哪个进程删的。把它和归属图对照,令人困惑的关机就会变成一份很短的候选名单。
例外也有代价。为了躲开冲突而把整类设备标为不受管理,等于把这份状态交给了没有人,这是决定,不是修复。