早年的临时方案把 OpenVPN 可执行文件挪到了别处,并在原路径留下一个 shell 包装脚本。几个月后升级到来,撤销这个方案就变成猜谜:到底哪个文件才是真正的客户端。命令名、服务里配置的可执行文件、软件包自己的文件清单,这三者可能指向不同对象;只修其中一个而不动其余,结果是一台看起来修好了、行为却更糟的主机。

先看服务实际启动的路径

终端和 systemd 单元解析可执行文件的方式并不相同。shell 会搜索 PATH;单元直接写死路径,而 drop-in 覆盖可以在不改动你正在阅读的那个文件的情况下替换它。正是这个差别造成了本任务里的大部分困惑。它也决定了你的修复该针对哪个文件。

问单元实际运行什么,包括修改它的 drop-in,并读取最终的 ExecStart 行,而不是你想当然认为权威的那一段。然后顺着该路径穿过任何符号链接,找到最终文件。以 exec 钻进隐藏目录收尾的包装脚本,是这类老修复的常见摆法。

动手之前先把解析后的路径记下来。

systemctl cat [email protected] | grep -n 'ExecStart'
readlink -f "$(command -v openvpn)"

把命令名和服务路径对照起来

两个答案经常不同,而这种不同并不自动等于故障。NetworkManager 的插件可能启动自己的路径,容器又可能挂载另一条路径。

关键在于弄清楚哪个所有者启动了承载流量的进程。如果单元运行的是 /usr/local/sbin/openvpn-wrapper,而你的 shell 解析出的是 /usr/sbin/openvpn,那么修第二个文件对服务毫无影响。

先查每个候选文件属于哪个软件包,再判断它是包管理的还是本地放置的。没有归属软件包的文件,是有人故意放在那里的文件,删除之前它应当有名字、有归属、有理由。反过来的错误同样常见:因为某篇论坛帖用了同一个目录,就用旧备份的二进制覆盖软件包文件。

软件包文件的事,交给软件包数据库来说

如果软件来自 Debian 软件包,软件包数据库能告诉你它的文件是否仍与安装时一致。这是一个范围很窄的完整性判断,而不是安全结论;在决定修什么的时候,这个区别很重要。不一致意味着文件在安装之后被改过,可能是你的旧方案,也可能是合法的本地修改。输出并不能判定是哪一种,所以要把它当作线索,而不是结论。

运行校验并读取输出,而不要把空结果当成任何事情的证明。

dpkg -S /usr/sbin/openvpn
dpkg --verify openvpn

dpkg 手册说明该校验会把已安装文件与本地记录的元数据作比较,并在存在时使用保存的校验和。它能发现被改动的软件包文件,却无法告诉你是不是换成了另一个二进制在运行。

修复前先记录现状

收集解析后的启动路径、文件与软件包的关系、包装脚本的位置,以及引入它的变更记录。如果包装脚本里含有以后还需要的集成工作,就把它复制到受保护的地方。

在读过包装脚本之前,不要把它贴进支持帖,因为这些脚本有时带着凭据或网关细节。

动手时记录服务使用哪些配置文件、谁正连着,因为重启隧道可能切断你用来管理主机的会话。

验证启动,然后清理包装脚本

修复之后启动服务,确认进程跑的正是你想要的路径。手动执行一次版本查询只能证明文件本身可用,不能证明单元在用它。

接着重新连接客户端,确认配置文件仍然能通过认证,因为忽略原始参数的二进制替换会以看似证书问题的方式失败。

通过引入它的同一份变更记录来清理被替换掉的包装脚本。修完之后要说明:哪个可执行文件在跑、为什么、删掉了哪个文件;把文件名放回去然后祈祷,并不是同一回事。

相关文章