OpenVPN 中 persist-tun 与 persist-key 到底保住了什么
两个选项都只覆盖一个存活进程内部的软重置。它们不会在停止后保留接口,也不是流量阻断策略。
即使设置了 persist-tun,停止服务仍会移除接口。这是选项在按文档工作,而不是故障。该选项描述的是运行中进程内部的一条重启路径,而 systemctl stop 并不是这条路径。
把两个名字放在一起读,设计就清楚了。一个保留描述符,另一个保留密钥材料,两者存在的原因都是权限被丢弃之后会发生什么。
两种资源与它们所属的重置
OpenVPN 在两种常见情况下会发出自己的重启信号。显式的 SIGUSR1 会这样做,由对端失联触发的 ping-restart 也一样。两者都让进程继续存活并重新执行连接设置,选项的价值正体现在这里。
| Event | TUN/TAP device | Key and auth files | Addresses and routes | up/down hooks |
|---|---|---|---|---|
Soft reset, from SIGUSR1 or from a ping-restart the daemon sends itself | survives only with persist-tun | survive only with persist-key | survive with the device, otherwise rebuilt | run again only when restart hooks are enabled |
Configuration reload, SIGHUP | recreated | re-read from disk | rebuilt once the device returns | run again |
| Service stop | lost | re-read at the next start | removed | run at the next start |
这两个选项改变的只是软重置那一行,而它们跳过的工作在繁忙链路上正是昂贵的那部分。重新打开设备会拆掉挂在它上面的地址和路由,重建这些又可能丢掉重置开始时仍在途中的报文。停止则会销毁同样的对象,且没有任何保留它们的选项。
这些选项究竟为什么存在
经过加固的 OpenVPN 服务器通常以 root 启动,打开密钥和设备,然后降到无特权用户。降权之后,有些操作就彻底没了。读取权限为 0600 的密钥文件、创建网络接口或修改路由,都可能被拒绝。
没有 persist 选项时,一个安静到足以触发 ping-restart 的对端就会逼出这些操作。即使配置毫无变化,重连也会失败。进程看上去像是无缘无故地死去,而日志显示的是权限错误,不是网络错误。
有了它们,软重置会复用特权阶段已经取得的东西。这里没有魔法,进程也没有真的扛过什么。资源的获取只是被推迟了。
读第一个错误,而不是最后一个
重置失败时,要读第一个错误,而不是最后一个。受保护的密钥、auth 文件、接口 ioctl 和外部钩子是四种不同的资源。保住其中一个,并不说明能否访问其他几个。调用防火墙工具的钩子仍然需要该工具要求的权限。
钩子有自己的开关。OpenVPN 手册 把 persist 选项与 up-restart 配在一起,后者决定重启后是否会再次运行 up 和 down 脚本。因此,接口仍然在线并不能告诉你 resolver 集成是否刷新过。
# which restart path just happened?
journalctl -u openvpn-client@office --since '10 min ago' | grep -E 'SIGUSR1|ping-restart|Restart pause|NOTE:'
# did the interface survive, and do its routes still exist?
ip -brief link show tun0
ip route show dev tun0
这一对命令能在几秒内区分两种故障模式。接口还在但路由缺失,是钩子或路由的问题。 接口消失,则意味着进程确实结束了。
保留下来的接口不是 kill switch
如果要求是流量绝不能离开隧道,保留设备并不能做到。另一地址族的路由、第二条默认路由,以及进程完全退出的情况,都仍在该选项的范围之外。
把两项要求分开处理。跨重连保留隧道对象,对守护进程只是便利。隧道断开时阻断出站流量,是带自己的规则和自己的测试的防火墙策略。把两者混为一谈,得到的配置看上去像在防御,行为却只是尽力重连。
先给事件命名,再作诊断。软重置、连接尝试失败和停止服务是三种行为不同的三个事件,只有第一个才是这些选项所描述的。