ESP32-C3 Adblock 项目通过将广告和跟踪域名存储为 40 位 FNV-1a 哈希值在 flash 中(而非作为字符串存储在 RAM 中),实现了一个 DNS sinkhole 来拦截广告和追踪域名。这种方法使设备能够在仅使用约 50 KB RAM 的情况下维护 537,000 个域名的拦截列表,而如果直接存储域名字符串则需要约 2.5 MB RAM。系统通过对排序后的哈希表进行二分查找来执行查找,根据项目文档报道,查询解析时间约为 10 毫秒。

从核心来看,该设备作为一个 UDP DNS sinkhole 运作:当 DNS 查询到达时,它提取域名,计算其 FNV-1a 哈希值(带有父后缀以进行子域匹配),并在 flash 中存储的哈希表上执行二分查找。匹配时,它返回 0.0.0.0 以有效阻止该域名;未匹配时,它将查询转发给上游 DNS 解析器并中继响应。该项目还包含一个可通过 mDNS 访问的管理 Web 仪表盘(地址为 http://c3adblock.local),用户可以在此查看统计信息、封禁特定客户端、添加自定义拦截域名,并通过浏览器界面配置拦截列表和固件的空中更新(OTA)。

显示 ESP32-C3 Adblock DNS sinkhole 带哈希表和 Web 仪表盘的示意图
ESP32-C3 Adblock 系统概览:UDP DNS sinkhole、 flash 中基于哈希的拦截列表以及管理 Web 仪表盘github.com

该图像展示了文章中描述的 UDP DNS sinkhole 机制和 Web 仪表盘,展示了 ESP32-C3 广告拦截器如何处理 DNS 查询并提供用户管理。

尽管采用了这种创新方法,但项目承认其基于哈希的拦截方法存在固有限制。使用 40 位哈希存储 537,000 个域名时,系统预计会出现大约一次哈希碰撞,即未被拦截的域名与被拦截的域名共享相同哈希值,导致误拦截(过度拦截)。虽然文档指出两个被拦截域名之间的碰撞无关紧要(因为两者都应被拦截),但它未详细说明除了 Web 仪表盘的 /unblock API 之外的解决误拦截碰撞的机制。此外,由于设备的技术限制,它无法实现诸如正则表达式或通配符等更复杂的拦截规则;这些规则在编译拦截列表时会被跳过,这限制了其拦截能力,相比更高级的解决方案有所不足。