防火墙编辑的死亡开关
家庭实验室自动化中最令人恐惧的一行代码,就是编辑你正通过 SSH 连接的路由器上的防火墙规则那一行。
以下是 Claude Code 和我如何依然进行编辑的方法。
恐惧所在
我需要将 UDM Pro 上名为 “Block inter-VLAN traffic” 的规则从 accept 改为 drop。这条规则长期以来一直配置错误——被设置为 accept,使得上面所有按流量的允许规则都被短路了——而将其重新关闭正是目的所在。执行变更的编排器是我家庭网络上的一台 NixOS 虚拟机。如果这次翻转切断了该虚拟机(或我自己的 SSH)所使用的路径,我将被锁在自己的路由器之外,没有控制台回退。
解决方案不是"小心一点"。解决方案是让危险的编辑在我未确认没问题的情况下自动恢复。
你以前见过这种模式。在 macOS 或 Windows 上更改显示器分辨率,系统会应用十五秒钟,同时显示一个倒计时的"保留这些显示设置?“对话框。如果你的屏幕变黑了,你什么都点不了——这正是重点所在。默认结果是回滚。确认是可选的。
这正是我们在修改规则之前对路由器防火墙翻转所需要的。
技巧
udm_set_firewall_rules.py --flip-with-revert 300 --apply
含义:“翻转规则,但在 300 秒后自动恢复——除非我告诉你不要这样做。”
按顺序执行的操作:
- 快照。 GET 当前规则,并将完整的 JSON 负载存储在 UDM 的
/root/.udm-flip-revert/payload-<id>.json。 - 准备恢复。 在负载旁边写入一个小型 shell 脚本,该脚本将快照重新 PUT 到 UDM API。
- 调度恢复。
systemd-run --on-active=300s --unit=udm-flip-revert-<id>将脚本作为临时计时器排入队列。 - 翻转。 PUT 新规则(
action: drop)。
现在你有 5 分钟的窗口来验证:
✓ flipped 'Block inter-VLAN traffic' to action='drop'
⏱ auto-revert scheduled (~300s)
TO KEEP THE FLIP: ssh udm 'systemctl stop udm-flip-revert-66c1d…timer'
TO ROLL BACK NOW: ssh udm 'systemctl stop …timer; bash /root/.udm-flip-revert/revert-….sh'
WAIT IT OUT: do nothing — timer will revert in ~300s
三种结果:
- 成功了。 停止计时器。翻转是永久性的。
- 破坏了某些东西。 停止计时器,运行恢复脚本。或者干脆停止输入——计时器将在 N 秒后触发,规则会自行恢复。
- 把我锁在外面了。 同样。计时器不需要我来触发。
第三种情况正是这一切存在的全部原因。
为什么用 systemd-run 而不是 at(1)
UDM Pro(Debian 11)没有附带 atd。但它有 systemd。systemd-run --on-active=Ns 创建一个临时计时器,触发一次后自动清理,这正是"在 N 秒后执行此操作然后消失"的形态。
ssh_udm(
f"systemd-run --on-active={seconds} --unit={unit} --collect "
f"--quiet /bin/bash {script_file}"
)
--collect 是关键标志——没有它,单元会停留在 failed/inactive 状态并使 systemctl 变得混乱。
注意事项
临时 systemd 单元存在于 /run 中,这是 tmpfs。如果 UDM 在恢复窗口内重启,计时器就消失了——翻转依然保持应用状态,没有死亡开关看守。
反直觉但真实:保持窗口短暂。带有小重启风险的 5 分钟窗口,比第 12 分钟 UPS 故障导致永久锁定的 1 小时窗口更安全。足够长以便验证,足够短以使"我是否忘记了待处理的恢复?“永远不成问题。
结语
死亡开关模式可以推广到 UDM 防火墙规则之外。任何你将要应用的可能切断你应用它的路径的变更——路由表、sshd_config、nftables、BGP——同样的形态都适用:
- 捕获当前状态
- 准备一个恢复它的脚本
- 安排脚本在 N 秒后运行
- 应用变更
如果在 N+ε 秒后你还在那里且一切正常,取消计时器。如果不是,计时器会取消你。
有了这个工具箱,我睡得更好了。