隧道关闭一天后,一个内部名称仍然解析到那台 VPN 服务器,resolver 文件也总是带着这条条目重新出现。在 Debian resolvconf 掌管状态的地方,那个文件由各家供给方的记录拼装而成,其中一条就是残留。删掉记录只需一分钟;证明它确实可以安全删除,才是真正的工作。这些关卡按顺序执行,任何一关失败都会终止流程,而不是把你送进下一步。

确认状态由 resolvconf 掌管

先辨认所有者,因为在 systemd-resolved 下出现同样的症状需要不同的命令和不同的修法。resolvconf 软件包在 /run/resolvconf 下维护一个数据库,并把 /etc/resolv.conf 指向它从该数据库生成的文件。两项检查就能定论:符号链接指向哪里,以及软件包是否已安装并处于活动状态。若指向 /run/systemd/resolve,说明用的是另一套设计,下面的一切都不适用。

dpkg -l resolvconf | tail -1
ls -l /etc/resolv.conf
systemctl is-active resolvconf.service

如果链接指向别处,或者根本没有这个软件包,就到此为止。借用了这个名字、由另一套 resolver 管理器提供的兼容外壳,并不掌管这个数据库。

数据库里存的是输入,不是答案

数据库保存输入,而文件是输出,所以列出输入才是看清哪个程序装上了那条你想清掉的记录的唯一办法。记录都很短,其中的键就是后面要用的把手。在判断哪条已过期之前先读一遍,因为看起来像 VPN 接口的名字可能属于另一个客户端。别把私有地址和内部搜索域放进共享的诊断信息;通常只看键就能认出这条记录。

sudo resolvconf --list
sudo resolvconf -i

第一条命令把供给上来的记录原样打印,不做处理;第二条列出当前提供 DNS 配置的接口。键通常由接口名加上供给它的程序拼成。resolvconf 手册描述了这些键所指向的数据库。

把键从输出里复制出来,不要重新拼一遍。一条条目不会因为某个旧脚本用过那个名字,就真的叫 tun0。

证明这条记录没有主人

当没有任何活动连接装过这条记录时,删除才是安全的。把键与创建它的那条连接对应起来,再确认那条连接已经消失。这个对应关系就是整道关卡,也是走向删除命令的路上最常被跳过的步骤。如果证据含糊,就把记录当作仍然有效,停下来。

进程名是很弱的证据。OpenConnect 会调用 vpnc-script,所以查 vpnc 进程并不能说明哪条记录是当前的。新连接还可能复用旧连接留下的接口名,这会让键看起来比实际更旧。把记录里的服务器地址与仍然在线的隧道地址作比较,一旦吻合就停下。

通过持有连接的管理器正常断开,是第一道解法。它会撤回那条连接装上的东西,而不碰其他供给方。

检查删除与重写

确认记录确已过期后,用精确的键删掉它,然后读取结果,而不是想当然。这条命令会改变整台机器上每个应用的解析状态,所以要在你能控制的窗口里执行。给键加上引号,因为里面有 shell 否则会展开的字符。代码块里的占位符代表你从列表中复制出来的键,不是一个字面字符串。

sudo resolvconf -d "RECORD_KEY_FROM_THE_LIST"
sudo resolvconf --list
resolvectl query host.corp.example || getent hosts host.corp.example

启用更新时,删除会运行更新脚本;关闭更新时,它会推迟更新,所以删掉记录和重写文件是两件独立的事。看文件之前先重读列表,确认键已经不在了。然后查询一个仍应通过剩余供给方解析的内部名称和一个公开名称,把两者与改动前看到的结果相比较。如果某个私有名称彻底解析不出来,说明那条记录还在承载它。

resolvconf -u 只运行那些更新脚本。它从不识别或删除过期记录,而用过期输入重新生成,只会再现同一个不受欢迎的文件。

被杀掉的断开钩子会把记录留下来

一次性的清理能恢复今天的状态,而下一次被中断的关机又会把记录放回去。沿着拆解路径走一遍:客户端的断开钩子、钩子调用的辅助程序,以及两者之一被杀时会发生什么。被中断的关机是常见源头,因为钩子根本没有执行。把钩子的退出状态记下一次,你就知道它是不是在悄悄失败。

把安装和清理交给同一个所有者。第二个脚本靠猜接口名,迟早会删掉另一条连接的记录,那比一开始的过期条目更糟。所有者还应当决定记录何时算过期,因为它知道是哪条连接装上的。

然后演练整个生命周期:连接、断开、再次列出记录。条目自己消失,才是修复站得住脚的唯一证据。

相关文章