工程草稿 · 未发布
0x00 序※
代理出问题最怕的不是“某个站打不开”,而是改完配置后整台机器失联:控制通道也被送进代理、自身路由绕回自身,最后没有办法把坏配置撤回来。
我要解决的是一个跨 Windows、Linux 和移动端都能复用的底层问题:以 TUN 为主的全局代理怎样热加载、怎样确认新配置真的可用、怎样在 5 到 10 秒内自动回退,以及 DNS 53 的自环到底该熔断还是转发。
0x01 目标不是热重载,是可回退的变更※
很多内核都支持 reload,但 reload 只表示“新配置被读到了”,不表示网络仍然可用。真正需要的是一次带事务语义的切换:
- 保存当前已知可用配置 (A);
- 校验候选配置 (B) 的语法、规则引用和监听端口;
- 加载 (B),同时启动一个 5–10 秒的回退计时器;
- 用不依赖待验证代理本身的探针检查 DNS、TCP、HTTPS 和控制面连通性;
- 探针全部通过才提交 (B),否则自动恢复 (A)。
这里的关键是“独立探针”。如果健康检查也走进同一条 TUN/规则链,配置把自己绕死时,检查结果没有意义。
0x02 内核与包装层分工※
跨平台部分不应试图手写三套网络栈。更实际的分工是:
- 内核:负责 TUN、协议、路由规则、DNS、入站和出站;sing-box 适合作为候选统一内核。
- 包装层:负责配置版本、预检查、启动/重载、探针、回退、日志和状态面板。
- 系统层:负责 Windows 服务、Linux systemd、网络权限、开机恢复和防火墙例外。
包装层不用碰包转发细节,反而更容易跨平台。它只把一次“改配置”变成一笔可提交或可撤销的事务。
0x03 自环不是普通故障※
自环通常有两个表现:
- DNS 请求送到本机监听的 53 端口,又被规则重新导回同一监听器;
- TUN 捕获到代理进程自己的上游连接,出站流量重新进入 TUN,形成循环。
DNS 自环的信号很明显:同一个查询在极短时间内重复、TTL 递减或不变化、源/目的地址反复落在本地监听地址、日志出现连续的同一 query ID 或同一域名链路。TUN 自环则要靠进程标记、路由表排除、出站网卡绑定和 loopback/私网例外共同防住。
处理原则不是“出了问题再转发”,而是:
- 命中明确自环:立刻熔断并记录原因,避免雪崩;
- 普通上游失败:按备用 DNS/备用出站做有限次数切换;
- 不确定的异常:保留抓包和事件日志,不静默吞掉。
把自环转发到另一个同路径的上游,常常只是把环路放大。
0x04 路由规则的顺序会改变结果※
分流规则不是静态清单,顺序就是行为。此前 ChatGPT 分流异常的一个直接原因,是 sniff 放在域名规则之后:已经被污染的 IP 先匹配到代理规则,后面再识别到真实域名也来不及了。
因此入口处理顺序应该明确:
- 先排除代理自身和控制面流量;
- 再做 sniff/DNS 映射,尽可能恢复域名语义;
- 再应用域名、进程、网段和地理规则;
- 最后才进入默认出站。
这条顺序同样适用于 Android:苹果正常、Android 异常并不自动说明远端节点坏了,Android 的 VPN 权限、私有 DNS、应用绕过策略、IPv6 与厂商网络栈都会让同一份规则表现不同。
0x05 平台差异别硬抹平※
Windows 上的 DAE、Linux 的策略路由和防火墙能力并不对等;SYNPROXY 更接近 Linux 内核网络能力,也不是一个跨平台 TUN 客户端该强行复刻的功能。
跨平台应该统一的是抽象:
- 开启/关闭 TUN;
- 写入候选配置;
- 发起健康检查;
- 提交或回退;
- 导出诊断包。
平台专有能力放成可选插件,而不是让所有平台都背同一套内核假设。
0xFF 跋※
一个可靠代理系统的核心不是“规则多”,而是“改错了还能回来”。TUN 内核解决转发,包装层解决变更安全,熔断机制解决自环,探针解决真假可用的判断。
先把回退和观测做出来,再追求更复杂的分流规则。这样即使 AI 参与调试,它也有明确的安全边界:可以生成候选配置、分析日志、建议修复,但不能让一次实验把控制通道一起带走。