ESP32-C3 DNS过滤实战:封禁设备、暂停拦截与自定义域名

发布时间:2026/11/3 21:48:04
ESP32-C3 DNS过滤实战:封禁设备、暂停拦截与自定义域名

家里网络里挂一台 ESP32-C3 做 DNS 层面的去广告,这个方案我前后用了小半年,最大感受是:真正决定这套东西好不好用的,不是拦截列表有多大,而是封禁设备、暂停拦截、自定义域名这三件日常操作顺不顺手。装好第一天你会觉得很神奇,第二周开始你就会发现——孩子的新平板要单独放行、家里来客人要临时开一下、某个 App 的推送域名要精准掐掉,这些全是"边用边调"的活儿。ESP32-C3 这块芯片只有单核 160MHz、400KB 左右的 SRAM,跑一个精简的 DNS 过滤服务刚好够用,也正因为资源紧,它的功能设计反而逼着人把逻辑想清楚:哪些是全局状态、哪些是每客户端状态、哪些是规则层的事。下面我按三大操作把踩过的坑和可以照抄的做法摊开讲,适合已经把这套东西跑起来、正在琢磨怎么把它用顺手的人看。

1. 三个操作背后其实是三层不同的东西

很多人第一次打开管理页面会懵:封禁设备、暂停拦截、自定义域名,看着都是"控制谁能访问什么",为什么不能合并成一个开关?我一开始也这么想,直到有一次把"暂停拦截"当成了"封禁设备"的反向操作,结果整晚有台设备在刷广告,第二天查日志才发现自己搞错了作用域。搞清楚这三者的层级关系,是后面所有操作不出错的前提。

1.1 一次 DNS 请求要经过的四道关口

把整个处理链路拆开看,一个来自局域网的 DNS 查询到达 ESP32-C3 之后,大致会走这么几关:先是客户端识别,从 UDP 包的源 IP 判断这是哪台设备;然后是全局开关,检查当前是否处于暂停状态;接着是规则匹配,拿域名去比拦截表和放行表;最后是上游转发,没被拦的查出去,被拦的按配置返回。三个日常操作恰好各自对应其中的一环:

  • 封禁设备,改的是第一关的客户端状态,粒度是"这台机器",影响它发出的所有查询。
  • 暂停拦截,改的是第二关的全局或分组状态,粒度是"一段时间内",和域名、设备都无关(除非你做了分组)。
  • 自定义域名,改的是第三关的规则数据,粒度和时间都无关,是永久性的配置变更。

这三层之所以不能合并,是因为它们的生命周期完全不同。设备封禁通常跟着设备的接入状态走,暂停拦截天然带倒计时,自定义域名是写进 Flash 的持久配置。如果硬把它们塞进一个"总开关",你迟早会遇到"我明明关掉了过滤,为什么这台设备还是打不开网页"这种问题——因为它的封禁状态还在生效。

提示:任何时候页面表现和预期不符,先按"客户端状态 → 全局状态 → 规则数据"这个顺序逐层确认,比漫无目的地翻日志快得多。

1.2 三者在生效范围与持久化上的差异对照

我把这三者的关键属性列了个表,贴在备忘里,排障时对着看,基本不会走错方向:

维度封禁设备暂停拦截自定义域名
作用对象单个客户端 IP(关联 MAC)全局或某个分组单个域名或域名后缀
生效范围该设备的全部查询范围内全部设备、全部域名所有设备
时间属性长期,直到手动解除通常带倒计时永久,直到手动删除
存储位置RAM +(可选)NVSRAM 标志位 + NVS 时间戳Flash 规则文件
断电后表现视是否持久化而定需要靠时间戳恢复剩余时长完全保留
典型误用想临时放行却去封了设备忘了暂停还在生效父域把子域一起带走了

这张表里最容易被忽略的是"断电后表现"那一行。ESP32-C3 没有板载 RTC,断电重启之后系统时间是从零开始的,必须靠网络对时才能恢复。如果你在暂停拦截的实现里只存了一个remaining_seconds,重启后这个值还在,看上去没问题;但如果你存的是"结束时刻",而时间还没同步上来,那么比较逻辑就会得到一堆莫名其妙的负数。这个坑我在第三部分会详细讲。

1.3 ESP32-C3 的资源约束反过来决定了功能该怎么做

为什么要在意芯片规格?因为它直接限制了你能不能用"最直觉"的做法。400KB SRAM 里,Wi-Fi 协议栈和 lwIP 就要吃掉一大半,留给 DNS 服务的堆空间通常在几十 KB 到一百多 KB 的量级。这意味着:

  • 规则表不能无限大。常见家用路由器上那种几十万条的列表,在这块芯片上塞不进去,实际能舒服跑起来的量级通常是几万条域名,而且要用紧凑的存储结构(比如按域名倒序排列的前缀树,或者哈希桶)。
  • 不能靠"删规则"来实现暂停。把几万条规则从 Flash 读出来、清空、再写回去,既慢又伤 Flash 擦写寿命(ESP32-C3 的 Flash 擦写次数典型值是十万次量级,天天这么干很快就到寿命了)。所以暂停必须做成一个内存标志位,匹配流程照走,只是在命中后跳过拦截动作。
  • 不能给每个设备存一份完整规则副本。设备级的差异必须用一个轻量的状态表来表达,比如一张最多存二三十条记录的客户端表。

理解了这一层,你会发现后面所有操作的"奇怪设计"其实都是被逼出来的合理选择。比如为什么暂停拦截只支持固定的几个时长档位而不是任意输入——因为省掉了一个文本输入解析和范围校验的代码路径,在只有几百 KB 可用堆的情况下,少一个分支就少一分崩溃风险。

2. 封禁设备:DNS 服务器眼里的"设备"到底长什么样

这是三大操作里最容易想当然的一个。很多人以为在页面上点一下"封禁",路由器就知道是哪台机器了,实际上 DNS 服务收到的 UDP 包里只有源 IP 地址,没有任何设备标识。你看到的设备名、MAC 地址,全都是系统额外维护的一张映射表查出来的。这个认知差异,直接导致了后面一大半的排障问题。

2.1 用 IP 当主键,MAC 只是显示用的标签

一个 DNS 查询到达时,代码能拿到的就是源 IP 和源端口。所以设备封禁在实现上必然是一张IP → 状态的表。那 MAC 从哪来?从 DHCP 租约表里关联。如果你的 ESP32-C3 同时还兼做 DHCP 服务器(很多这类固件都这么干),那它手上就有完整的租约信息:谁在什么时间拿了哪个 IP、对应哪个 MAC。如果 DHCP 还是交给上游路由器做的,那这块芯片就只能看到 IP,MAC 需要靠 ARP 表或者干脆拿不到。

这就引出一个很实际的问题:封禁的稳定性取决于 IP 的稳定性。默认情况下 DHCP 租约到期续租,客户端通常会拿到同一个 IP,但这不是保证。设备断电几天再上线、或者局域网里设备数量变动,都可能让 IP 漂移。漂移之后你封禁的就不是原来那台机器了。

我的做法是两步走:

  1. 先在上游 DHCP(或者这套固件自带的 DHCP 服务)里,给要做管控的设备建静态租约,把 MAC 和 IP 绑死。
  2. 再来做封禁,此时封的是 IP,但实质上等价于封了那台设备。

如果懒得配静态租约,还有个折中方案:在封禁记录里同时存 IP 和 MAC,匹配时以 IP 为主,但每次命中后回查一下 ARP 表,发现 MAC 对不上就自动失效这条规则并记一条日志。这个逻辑不复杂,但能挡住大部分"封错了人"的尴尬。

2.2 三种处理方式:黑洞、拒绝、透传,选错了会很麻烦

确定要封某台设备之后,还有个更细的选择:封到什么程度。这三种做法我都试过,体验差别很大:

处理方式DNS 返回设备侧表现适用场景
黑洞(返回 0.0.0.0)A 记录指向 0.0.0.0连接超时,页面一直转圈想让对方明确感知到"被限制"
拒绝(REFUSED)RCODE=5部分系统会立刻报"DNS 解析失败"快速定位问题,日志清晰
不存在(NXDOMAIN)RCODE=3表现和域名真的不存在一样干扰最小,适合长期静默限制
完全透传正常上游结果完全不受过滤影响只想让它不过滤,不想让它断网

这里有个反直觉的点:返回 NXDOMAIN 反而是"最狠"的一种。因为设备会认为这个域名真的不存在,很多 App 的容错逻辑是"域名解析失败就重试几次然后放弃",用户体验上就是加载慢、功能缺失,但不会报明确的错误,用户也很难判断是网络问题还是别的原因。而返回 REFUSED 至少让客户端的系统日志里留下清晰痕迹,你自己排障时也好定位。

至于"完全透传",它和"封禁"其实是两种东西,但很多固件把它们放在同一个设备列表里用状态区分,这就很容易混淆。我的建议是:如果你只是想"让这台设备不受过滤影响"(比如工作用的机器,某些开发域名被误拦了),用透传;如果是"这台设备我不想让它上网"(比如孩子的平板在写作业时间),那才用拒绝或 NXDOMAIN。

2.3 操作流程与字段说明

实际配置下来,一个完整的封禁记录大概包含这么几个字段,不同固件的字段名不一样,但语义基本一致:

设备标识: living-room-tv IP 地址: 192.168.1.42 MAC 地址: aa:bb:cc:dd:ee:ff (可选,用于校验) 处理方式: nxdomain | refused | blackhole | bypass 生效时段: 全天 | 自定义时间窗 备注: 电视开机广告

注意:如果固件支持"生效时段",一定要确认它用的是本地时间而不是 UTC。ESP32-C3 靠 SNTP 对时,默认拿到的往往是 UTC,如果你按 UTC 配了 22:00 到 06:00,实际生效时间可能整整差出八小时,这种错误排查起来非常费劲。

配置完成之后怎么验证?别急着去设备上开网页试,先在局域网里用另一台机器做定向查询,把源 IP 伪造是不现实的,所以更靠谱的验证方式是在目标设备上执行一次查询,或者干脆看服务端的实时日志——好的固件会打印"来自 x.x.x.x 的查询 example.com → 命中客户端规则 → 返回 NXDOMAIN",一眼就能确认规则生效了。

2.4 封了没效果?先排查客户端的 DNS 逃逸

这是我踩得最深的一个坑。有一段时间我发现某台设备明明在封禁列表里,广告却照刷。查了半小时服务端日志才反应过来:这台设备压根没在往我这儿发查询。

原因有三类,都很常见:

  • 系统级备用 DNS。有些设备在首选 DNS 超时或返回异常时,会自动切换到网络里通告的备用 DNS,或者干脆切到内置的公共 DNS。
  • 加密 DNS。较新的移动系统默认开启了加密解析,查询直接走加密通道,局域网里的明文 DNS 服务器完全看不到。
  • 应用内置解析。部分应用不调用系统解析器,自己实现一套。

排查方法很简单:在服务端日志里按源 IP 过滤,看这台设备到底有没有查询记录。如果一条都没有,那问题不在过滤规则,而在流量路径。此时要么在路由器层面做 DNS 重定向(把 53 端口的出网流量劫持回本地),要么在设备上手动关掉加密解析选项。

实操心得:做设备封禁之前,先花两分钟确认"这台设备确实在用我的 DNS",能省掉后面一小时的困惑。日志里源 IP 出现频率就是最好的证据。

2.5 解封与临时放行的正确姿势

解封很简单,把记录删掉或者把状态改回正常即可。但我更推荐的做法是保留记录、切换状态,而不是直接删除。原因是你可能过几天又要封一次,重新走一遍"查 IP、查 MAC、填备注"的流程很烦;而且保留记录之后,历史备注还在,半年后你看到这条还能想起来当初为什么封它。

临时放行则是另一个需求:比如孩子的平板平时限制,周末放开。这时候不要用"暂停拦截",因为暂停是全局的,会把所有设备的过滤都关掉。正确做法是给这条封禁记录加一个时间窗,或者干脆在需要的时候手动切状态。前者更省心,后者更可控,看你自己的习惯。

3. 暂停拦截:看起来最简单,实际最容易出事

"暂停"这个按钮是整套系统里点击率最高的,也是最容易埋雷的。表面逻辑就一句话:暂停期间不拦截,到点自动恢复。但真要做到"可靠",需要处理的问题比想象中多——尤其是断电、重启、时间同步这几件事凑到一起的时候。

3.1 三种粒度:全局、分组、单域名,别用错层级

严格来说"暂停拦截"可以有三个粒度,能力从大到小:

  • 全局暂停:所有设备、所有域名都不拦。适合的场景是"我要排查某个网页打不开是不是被误拦了",或者"今天有重要会议,任何异常都不能出"。
  • 分组暂停:只暂停某一类设备(比如"访客设备"组)。适合家里来了客人,你不想让他们的设备受限制,但自己的设备继续过滤。
  • 单域名放行:严格说不算"暂停",是往放行表里加一条临时规则。适合"就这一个网站要用,其他继续拦"。

很多人一遇到问题就点全局暂停,然后忘了恢复,结果第二天发现广告全回来了,还以为是固件出 bug。我的习惯是:能用单域名放行解决的,绝不用全局暂停。因为单域名放行的影响面最小,事后也容易追溯——放行表里能看到你加了什么,而全局暂停一旦过期就什么都不留。

3.2 倒计时怎么存:RAM 标志位 + NVS 时间戳

这是实现层面最有意思的部分,也直接决定了你按下暂停后能不能放心走开。ESP32-C3 上,millis()返回的是开机以来的毫秒数,重启就归零。所以你不能只存一个"还剩多少秒"在 RAM 里——重启后这个值虽然还在(如果存在 NVS 里),但它对应的"现在"已经变了。

正确的做法是存绝对时间戳:

暂停开始时刻: 1735689600 (Unix 时间戳,来自 SNTP) 暂停时长: 1800 秒

然后每次判断时,用当前的 Unix 时间戳去减。这样即使中途重启,只要重启后能重新对上时间,剩余时长就自动算对了。

但这里有个致命的边界情况:如果重启后网络还没通、SNTP 还没同步,当前时间戳是多少?很多实现里这时候会返回 0 或者一个很小的值,于是now - start变成一个大负数,判断逻辑直接失效——要么永久暂停,要么立即恢复,全看你代码里怎么写的比较符。

我遇到过最坑的一次是设备断电重启后自动恢复了拦截,但界面上的倒计时还在正常走,显示"还剩 12 分钟"。原因是界面读的是 NVS 里的旧值,而实际匹配逻辑走的是另一条路径。这种"界面和实际不一致"的问题,比功能直接失效更难发现。

稳妥的写法是加一个状态机:

状态条件行为
时间未同步SNTP 尚未成功过暂停状态按"未知"处理,默认保持暂停(宁松勿紧)
正常暂停中now < start + duration不拦截
已过期now >= start + duration恢复拦截,清除标志位
时钟回跳now < start视为异常,清除暂停状态并记日志

"时间未同步时默认保持暂停"这个选择,是我踩坑之后改的。原来的逻辑是默认恢复拦截,结果有一次路由器重启,ESP32-C3 比路由器先起来,时间没同步上,暂停状态被误判为已过期,家里正在看的一个需要临时放行的页面直接挂了。改成"宁松勿紧"之后,最坏情况是暂停时间比预期长一点,需要手动点一下恢复,但不会出现"莫名其妙又拦上了"的情况。

3.3 排查"网页打不开"时的正确使用顺序

暂停拦截最实用的场景其实不是"我要看广告",而是排障。一个页面打不开,可能是 DNS 被拦、可能是网络本身有问题、可能是网站自己挂了。用暂停来二分定位,顺序很重要:

  1. 先看服务端日志,确认这个域名到底有没有被拦。有记录且命中拦截,那基本可以确定是误拦。
  2. 加一条单域名放行,再刷新页面。好了,说明就是这条规则的问题,去放行表里留着它。
  3. 如果加了放行还是不行,再试全局暂停。这时候如果好了,说明是别的域名也被拦了(一个页面往往要加载十几个域名,你只看到了主域名)。
  4. 全局暂停也不行,那就不是过滤的问题了,去查上游网络。

这个顺序的价值在于:每一步都在缩小范围,而且每一步都有明确的判断依据。直接上全局暂停虽然快,但你放弃了所有诊断信息,事后什么也学不到。

提示:全局暂停期间记得看一眼日志里的"未拦截"记录数量。如果暂停 5 分钟内出现大量本该被拦的域名,说明这台设备的日常流量里广告请求密度很高,可以考虑针对性地把其中几个高频域名加进永久拦截表。

3.4 暂停期间的缓存问题:TTL 和负缓存

还有一个很隐蔽的点:DNS 结果会被客户端缓存。你在服务端暂停了拦截,但设备上可能还存着之前"被拦截"的那个结果,TTL 没到期就不会重新查询。表现出来就是"我明明暂停了,怎么还是打不开"。

解决思路有两个:

  • 把拦截响应的 TTL 设得很短,比如 30 秒甚至 10 秒。代价是客户端会更频繁地查询,对这块小芯片来说是额外负载,但 10 秒的 TTL 在家庭规模(几十台设备)下完全扛得住。
  • 接受现实,暂停之后等一会儿再刷新,或者手动清一下设备缓存。

我选择的是前者,把拦截响应的 TTL 设成 30 秒。这个值是个折中:既不会让客户端缓存太久导致暂停失效,也不会让查询频率高到影响性能。顺便说一句,负缓存(NXDOMAIN 的缓存)也要注意,有些系统对 NXDOMAIN 的缓存时间比普通记录更长,这也是为什么我用 REFUSED 而不是 NXDOMAIN 做设备封禁——REFUSED 通常不会被长时间缓存。

4. 自定义域名:把通用列表调成自家的规则

拦截列表再全,也总有覆盖不到的地方。用了几个月之后你会发现,真正让你烦的那几个广告位,往往来自一些不太出名但很固定的域名。自定义域名这个功能就是干这个的——但它的坑主要集中在"匹配规则"和"误伤"上。

4.1 放行优先于拦截,这个顺序不能反

所有规则匹配的第一原则:放行表的优先级高于拦截表。也就是说,哪怕一个域名同时出现在两张表里,最终结果也应该是放行。这个设计的理由是:拦截错了会导致功能不可用(用户会立刻发现并抱怨),放行错了只是多看到一个广告(用户可能根本不在意)。两者代价不对等,所以优先保证"能用"。

理解这一点之后,很多"奇怪现象"就解释得通了。比如你手动把一个域名加进拦截表,结果没生效——八成是它已经被某个上游列表的放行规则覆盖了,或者它的父域在放行表里。

实际操作中,我建议自定义域名的时候分成两个独立的输入框,而不是一个带前缀的文本框:

拦截域名: ads.example-a.com tracker.example-b.net 放行域名: api.example-c.com cdn.example-d.org

分开填的好处是不容易手滑把方向搞反。我见过有人把要放行的域名填进了拦截框,然后花了半天排查为什么这个网站打不开。

4.2 匹配规则:精确、后缀、通配符,三种写法别混

域名匹配的写法有好几种流派,混用是出错的重灾区。常见的有这么几类:

写法含义匹配示例
example.com精确匹配该域名只匹配example.com,不含子域
*.example.com匹配一级子域匹配a.example.com,不匹配a.b.example.com
.example.com匹配该域及其所有子域匹配example.com、a.example.com、a.b.example.com
`example.com^`

最坑的是第一行和第三行的区别。很多固件为了"省事",把不带前缀的域名默认当成"含所有子域"来处理,这在拦截场景下通常没问题(多拦一点无所谓),但在放行场景下就是灾难——你想放行api.example.com,结果把整个example.com都放行了,包括它的广告子域。

我的经验是:放行一律用精确匹配,拦截才用后缀匹配。这样即使写错,影响也是可控的。

4.3 父域和子域:一条规则可能带走一大片

这是自定义域名最容易出事的地方。假设你把example.com整段拦了,那么mail.example.com、pay.example.com、login.example.com全部一起被拦。有些网站的所有服务都挂在同一个主域下,一拦全废。

判断方法很简单,加规则之前先想一想:这个域名下面有没有你需要的服务?如果不确定,就先只用精确匹配拦最具体的那个子域。比如你要拦的是ads.example.com,那就只写ads.example.com,别图省事写成example.com。

还有一种情况是"看起来是子域,其实不是"。比如example.com.cn和example.com是两个完全不同的域名(不同的注册主体),后缀匹配example.com是不会误伤example.com.cn的,因为域名匹配是按标签(label)边界对齐的,不是简单的字符串包含。这一点倒是可以放心。但反过来,如果你手写了一个简单的字符串contains判断,那就真会误伤——所以匹配实现一定要按标签边界来。

4.4 共享 CDN 域名:这类绝对不能整段封

有一类域名我建议列进"永久放行"白名单,就是各大 CDN 和云服务的公共域名。原因很直接:它们承载了几百上千个不同网站的资源。你把某个 CDN 域名封了,可能顺手把几十个正常网站的图片、脚本全干掉了,表现出来就是"某些网站排版错乱、按钮点不了",而且极难联想到是 DNS 拦截导致的。

典型的判断依据是:如果这个域名你在多个不相关的网站的服务端日志里都见过,那它大概率是共享基础设施,不能封。我在放行表里固定留了几条这类记录,遇到页面样式异常时先检查它们有没有被误拦。

顺带提一下 CNAME 的问题。有些广告域名的解析结果是 CNAME 到一个共享域名,如果你只按最终解析结果匹配,就会误伤共享域名;如果只按查询的原始域名匹配,又拦不到换了壳的变体。稳妥的做法是只按用户查询的原始域名做匹配,不要去追踪 CNAME 链。追踪链看起来更"聪明",实际上在资源受限的设备上既费内存又容易误伤,收益远小于风险。

4.5 规则写入 Flash 的几个注意事项

自定义域名最终要持久化到 Flash 里,这里有几个实操层面的细节值得说:

  • 别频繁写。ESP32-C3 板载 Flash 的擦写寿命是十万次量级,听起来很多,但如果你每次改配置都整块重写,一年下来也可能上万次。好的做法是把规则攒一攒再写,或者只写变更的那一页。
  • 注意分区大小。自定义规则和系统自带的拦截列表通常共享一个存储分区,规则加多了会挤占空间。加之前看一眼剩余空间,别等到写失败才发现。
  • 写入后要重载内存表。有些实现写完 Flash 就完事了,内存里的规则表还是旧的,得重启才生效。改完规则之后立刻做一次查询验证,能立刻发现这个问题。
  • 注意规则数量上限。前面说过,这块芯片的哈希表或前缀树是有容量上限的,超出之后要么写入失败,要么新规则被静默丢弃。界面上最好能显示"已用 X / 上限 Y",否则你会疑惑为什么加了规则没反应。

实操心得:我习惯在批量加规则之前先导出一次当前配置做备份。ESP32-C3 的配置分区一旦写坏,恢复起来要么重新刷固件,要么手工重建规则,都挺麻烦。备份文件几十 KB,存手机里就行。

5. 把三个操作串起来:几个真实场景的处理流程

单独看每个操作都不难,难的是遇到具体问题时快速判断该动哪一个。下面这几个场景是我这半年里反复遇到的,处理流程可以直接照搬。

5.1 智能电视的开机广告:设备封禁 + 域名拦截组合用

电视开机广告是最好解决的,也是最容易解决的过头的一类。我的处理顺序是:

先只看不改,跑两三天,让日志把电视发出的所有 DNS 查询记下来。然后在日志里挑出那些明显是广告和推送的域名(通常出现在开机后头 30 秒内,且重复出现)。把这些域名加进拦截表,观察一周。如果还有残留,再考虑对这台设备做更严格的管控。

这里不建议一上来就封禁设备。因为电视除了广告,还有系统更新、应用商店、投屏协议,全封了会影响正常使用。设备封禁应该留给"这台设备在规定时段内不该联网"这种场景,而不是用来治广告。

5.2 家里来客人:分组暂停而不是全局暂停

客人设备接进来,最省事的做法是给它们单独划一个分组,然后对这个分组做"不拦截"策略。这样你的设备继续过滤,客人的设备完全不受影响,谁都不用折腾。

如果没有分组功能,退而求其次用全局暂停,但要设一个明确的时长,比如 4 小时。千万别选"无限期"——我干过一次,忘了恢复,一周后才发现家里的过滤全停了。

5.3 固件升级前后的配置处理

升级固件是唯一一个会把三个操作全部重置的场景,所以流程要格外小心:

  1. 升级前导出配置,包括设备列表、暂停状态(如果有)、自定义规则。
  2. 升级后先别急着导入,确认新固件的字段结构有没有变化。我就遇到过升级之后规则字段改名,导入直接失败的。
  3. 导入后做三项验证:设备封禁是否还有效、暂停状态是否已清空(升级后应该默认恢复)、自定义规则条数对不对。
  4. 观察一天日志,确认没有异常的大量拦截或大量放行。

这套流程走下来大概十分钟,但能省掉后面几小时的困惑。尤其是"暂停状态是否已清空"这一项——如果旧固件里存了个很长的暂停时间戳,新固件又正好用了不同的时间基准,那可能会出现"升级完过滤就失效了"的情况,而且界面上一点提示都没有。

最后再分享一个小技巧:不管哪个操作,做完之后都用同一条命令验证一遍——在局域网里对某个已知的拦截域名做一次查询,看返回结果对不对。这一条命令能同时验证规则加载、匹配逻辑、响应构造三个环节,比在浏览器里刷半天页面高效得多。我现在改完任何配置,都是先跑这一下,确认没问题再去实际使用。