节点死于解析

节点死于解析

一、第一台:机器活着,节点死了

晚上九点多,先是 j1 的节点被报挂了。登上去看:机器已经连续运行四天,sing-box 服务从四天前启动后一直 active,三个入站端口都在监听,防火墙没有拦截,磁盘还剩一成多。所有"机器死了"的常规嫌疑都被排除,它就是一台健康机器上躺着一个死节点。

往深一层查解析:在机器上做一次最普通的域名查询,直接超时;绕开系统解析、直查公共 DNS 服务器,立刻有结果。再翻 sing-box 的日志,2508 次解析失败一字排开——握手要解析的、出站要解析的、连对时要解析的域名,全部卡在十秒超时上。节点协议握手的第一步就是解析,解析不通,后面的一切配置、证书、密码都无从谈起。

二、第二台:同一种死法

查完 j1 不久,g2 的节点也被报挂了。同样的流程走一遍:机器活着,服务活着,端口监听着,系统解析超时,日志里 1122 次解析失败。两台机器、同一个晚上、同一种死法,这就不再是巧合,而是配置层面的通病。

病根在一条不起眼的依赖链上。这批机器的 sing-box 解析配置写的是"走本地系统解析",而系统解析又被 Tailscale 接管,只剩它一个转发地址。这个转发一旦失效,整条链就断了:系统查询超时,sing-box 跟着超时,节点在外面看就是暴毙。偏偏这条链平时毫无存在感——它工作的时候,没有任何人会想起它。

三、全队排查:谁用了哪条链

既然是通病,就把全机队七台机器一次查完。结果很说明问题:凡是解析走系统本地解析服务(systemd-resolved)的机器——g3、k1、k2——全部无恙,日志干净;凡是把解析押在 Tailscale 那条链上的,除了已经暴毙的 j1、g2,还有 g1 和 vn1 都还活着,但配置一字不差,属于雷已经埋下、只是还没踩响。

这种排查最怕的就是"现在能用"四个字。能用只说明转发此刻还活着,不说明这条链可靠。j1 和 g2 在今天之前,也是"能用"的。

四、修法:把解析从链里摘出来

修法没有玄机:把这几台 sing-box 的解析配置从"走本地"改成直连公共解析(1.1.1.1),让节点的解析不再经过系统、不再经过 Tailscale。动手顺序是固定的:先备份原配置,改完先跑配置校验,校验过了才重启服务,重启后逐项验收——服务在跑、端口在听、日志里不再新增解析失败。最后再单独拉起一个同款解析配置的测试实例,实际发两个请求出去,一个返回 204、一个返回 200,确认解析和出网是真的通,而不是"看起来通"。

j1、g2 是故障后修的;g1、vn1 是当晚拍板防患换的,流程一模一样。七台机器处理完,押在那条脆弱解析链上的节点清零。系统层面那条链本身还没动根治——那是另一个层面的决定,留待后面再说;至少节点先从链上摘了下来,不再陪它一起死。

五、同一天的另一课

也是这一天,一个部署在 Cloudflare Pages 上的代理隧道项目被平台封了,理由方向毫不意外:这类工具踩了平台明文的红线。项目删掉,事情翻篇,主站和其他项目毫发无损。但它和节点暴毙凑在同一天,倒像是一组对照实验:一边是自己的机器,死于一条没人注意的依赖链;一边是别人的平台,死于一条早就写明的规则。前者靠排查和验收防,后者靠动手之前先看清边界防。

说到底,节点这种东西,很少死于惊天动地的攻击,多数时候死于解析、证书、时间、磁盘这类"不值得专门看一眼"的小环节。运维的日常与其说是和攻击者斗,不如说是和自己的依赖链斗:知道每一环挂着谁、谁挂了会连坐到哪一层,然后在它断之前,先把它从关键路径上摘下来。

评论