只用 ping 的看门狗分不出隧道是坏是好
对公网发 ping 证明的东西比看上去少。要从隧道内部探测,先统计连续失败再行动,并把切换服务器当作独立决策。
看门狗到底帮忙还是添乱,取决于三件事:探测能区分什么、连续失败多少次才值得动手、以及动手是重连还是切换。一行对公网地址发 ping 的 cron 哪一件都答不好。它会把原本正常的隧道重连一遍,却把真正坏掉的隧道放着不管,而且两边都不留记录。值得保留的设计会把这三个选择明确写出来。
探测才是决定其余一切的那一环。
对公网发 ping 究竟证明了什么
对公网解析器发 ping,只能说明本地互联网路径是通的。它证明不了隧道在承载流量;而在全隧道配置下,ping 本身就走隧道,所以应答正常和隧道已经坏掉可以同时存在,客户端也仍在转发数据包。如果配置把域名查询也送进隧道,一次 DNS 失败就会被读成链路中断,触发一次根本修不好任何东西的重连。
两个方向的错误都不会出现在退出码里。 建立在这个信号上的看门狗,不过是按 cron 排程抛硬币。
去探测隧道另一侧真正活着的东西
ip -brief addr show tun0 ip route get 10.100.20.10 nc -z -w3 10.100.20.10 443
从内部探测,先做最便宜的那一项。接口是否存在,说明隧道有没有起来;查一条通往已知内网地址的路由,说明流量会不会走进隧道;对另一侧主机做一次 TCP 探测,说明那边是否真的有人应答。只看 echo 请求会被误导:许多内网主机乐于回应 TCP,却把 ICMP 丢掉,于是基于 ping 的看门狗会不停重连一条从未停止工作的隧道。
给探测设时间上限,并给它单独的退出状态。一次挂起三十秒的探测,会把看门狗变成自带延迟的故障检测器。
在单行脚本和循环之间做选择
* * * * * nc -z -w5 10.100.20.10 443 || myvpn reconnect
cron 条目只有一行、没有记忆,适合那种多一次重连也无所谓的笔记本。受监管的循环会维护计数,连续失手若干次才动手,从而避免一条不稳的链路引发重连风暴。无论选哪种,都要放在监管进程下运行,这样它崩溃后还能重启,并把记录写进日志。选择的依据是多一次重连要不要紧,而不是哪个版本更短。
failures=0 while sleep 30; do if nc -z -w5 10.100.20.10 443; then failures=0 else failures=$((failures+1)); fi if [ $failures -ge 3 ]; then myvpn reconnect; failures=0; fi done
那个循环统计的是连续失败,而不是某个窗口内的比例。窗口需要时钟,还要记住样本,手写看门狗里的大部分缺陷恰恰就出在这套算术上。
切换是另一个决策
换服务器和重连不是一回事。先拆掉旧链路,因为第一个客户端还占着地址时,第二个客户端启动就会撞车。切换之前先数连续失败,给尝试次数设上限,新链路起来之后再探测一次,而不是相信 connect 命令的退出状态。配置错了不该在一轮循环里把每台服务器都转一遍。
不要在全隧道内部去探测 VPN 服务器自己的公网地址。那项检查依赖的正是它要测的东西,而且它会在本该验证的路径已经消失时报告成功。
记录跑的是哪项探测、返回了什么、之后做了什么动作。有了这份记录,一次莫名其妙的掉线才会变成可诊断的事件。