README 的 Hardware 和 Build & flash (PlatformIO) 章节:C3 SuperMini、4 MB flash、no PSRAM;默认列表约100k entries。
esp32-c3-adblock:$2芯片承载537k域名的DNS广告拦截器
给家庭网络用的ESP32-C3 DNS拦截器,把域名哈希放进flash而不是RAM。
🧭 决策指南
为什么现在热: README强调$2 ESP32-C3、537k域名、约50KB RAM和约10ms匹配,并列出Tom's Hardware、XDA Developers和Korben报道;结合当日新增196星,材料足以说明低成本硬件承载大规模DNS列表是当前关注点。
适合,如果你
-
你有4MB ESP32-C3 SuperMini,想在无PSRAM设备上运行约100k默认blocklist。
-
你需要把DNS拦截器放进路由器USB口,并接受约10ms的哈希查找延迟。README 的 Hardware 和 Why this is interesting 章节:USB-A → USB-C dongle可接路由器;lookup约10 ms。
-
你希望首次USB刷写后,通过c3adblock.local维护blocklist和firmware。README 的 Build & flash (PlatformIO) 和 Over-the-air updates 章节:之后firmware与blocklist都可通过WiFi更新。
不适合,如果你
-
你必须同时使用537k ultimate列表和firmware OTA,而硬件只有4MB flash。README 的 Over-the-air updates 章节:OTA需要两个app slots,blocklist约250k上限;537k列表只能使用single-app partition table。
-
你的威胁模型包含可监听LAN流量的攻击者,且需要加密管理接口。README 的 Security 章节:所有流量是plain HTTP on :80,Basic Auth凭据以base64发送,不是加密。
-
你要把设备直接暴露给不可信网络,或依赖默认CHANGE_ME凭据运行。README 的 Security 章节:默认凭据公开;项目明确说明Basic Auth只是LAN trust boundary control。
-
你只有旧版apt PlatformIO,例如4.3.4。README 的 Build & flash (PlatformIO) 章节:distro/apt platformio package,例如4.3.4,会因AttributeError: ... 'resultcallback'失败。
前置条件
- ESP32-C3 board,tested on a C3 SuperMini,4 MB flash,no PSRAM needed
- Stable USB source,例如phone charger或router's USB port
- Current PlatformIO;README指出apt PlatformIO 4.3.4过旧
- 先配置src/secrets.h中的WEB_USER、WEB_PASS和OTA_PASS
- 首次USB刷写需要pio run -t upload和pio run -t uploadfs
第一步命令(README 原文)
cp src/secrets.example.h src/secrets.h
要注意
-
便宜或松动的USB-C→A适配器可能在WiFi发射时造成brownout。README 的 Hardware 章节:cheap/loose USB-C→A adapters can brown out the radio during WiFi transmit。
-
未修改secrets.h会继续启动,但串口告警并显示公开密码横幅。README 的 Security 章节:CHANGE_ME_WEB_PASSWORD和CHANGE_ME_OTA_PASSWORD会触发warning,但firmware仍会运行。
-
WiFi setup portal的C3-AdBlock-XXXX接入点仍是开放且未加密。README 的 Security 章节:setup portal access point is still open (unencrypted) by design。
-
自定义/addblock域名虽做HTML转义,网络OTA仍需OTA_PASS。README 的 Security 章节:custom names are HTML-escaped;ArduinoOTA requires OTA_PASS。
替代方案
-
传统ESP32 + PSRAM DNS sinkhole:当你需要把domain strings直接放进RAM,或可接受约$8的ESP32 + PSRAM硬件时更合适。README 的 Why this is interesting 章节
材料未说明
- README未给出高并发DNS查询量或长时间运行下的吞吐上限。
- README未说明上游resolver的默认地址、超时和失败重试策略。
- README未提供537k ultimate列表在不同分区表下的完整刷写命令。
- README省略了Enclosure、Gotchas和Done / how it could grow章节的具体内容。
- README未给出C3 SuperMini之外各ESP32-C3板卡的逐型号兼容性清单。
💡 深度解析
6
视情况
我需要在家庭 LAN 上启用 Web dashboard、blocklist 上传和固件 OTA;如果设备仍使用 HTTP Basic Auth 和开放配置 AP,这个项目的安全边界是否足够?
适合读者: 把 DNS 设备放在可信家庭 LAN、需要通过 Web 面板上传 blocklist 和 OTA 固件的嵌入式维护者
视情况,适合受信任的家庭 LAN,不适合公网、开放 WiFi 或存在可监听者的网络。
- README Security 章节要求所有状态变更接口使用
WEB_USER/WEB_PASS,网络 OTA 使用OTA_PASS,并要求自定义X-Requested-With: c3-adblock请求头来降低常见 CSRF 风险。 - 但管理界面完全是 HTTP :80,Basic Auth 只是 Base64;README 明确说开放/访客 WiFi、ARP spoofing 或其他链路监听者可以读取凭据。
- 未替换
CHANGE_ME_WEB_PASSWORD/CHANGE_ME_OTA_PASSWORD时,仓库示例中的公开占位值仍可登录;配置 APC3-AdBlock-XXXX也按设计保持开放且未加密。 - 所以该方案的边界是“可信局域网防普通误操作”,不是 TLS 或公网管理安全控制。
- README「Security」:状态变更接口需要 HTTP Basic Auth;OTA 需要 `OTA_PASS`;需要 `X-Requested-With: c3-adblock`
- README「Security」:Everything is plain HTTP on :80;Basic Auth credentials are base64
- README「Security」:默认占位密码公开;WiFi setup portal 的 AP 仍为 open(unencrypted)
适合
我需要在无 PSRAM 的 ESP32-C3 上处理 141k 到 537k 域名,同时控制 RAM 和查询延迟;40 位 FNV-1a 哈希加 Flash 二分查找是否适合?
适合读者: 研究低内存索引结构、要在无 PSRAM 的 ESP32-C3 上维护 141k 至 537k 域名列表的嵌入式算法开发者
适合,因为它直接针对无 PSRAM 的 RAM 和 Flash 约束设计,但必须接受哈希碰撞导致误拦截的概率。
- README 说明域名被转换为排序后的 40 位哈希并存入 Flash,141k+ 域名约占 0.7 MB,运行时约 50 KB RAM。
- 查询时计算 FNV-1a,并检查父级后缀,再对 Flash 哈希表二分查找;README 给出的典型代价约为 18 次 Flash 读取、包含 WiFi RTT 约 10 ms。
- README 的碰撞估计是 141k 域名约为 0 次,537k 域名约为 1 次;因此 40 位是存储规模、查询效率与误拦截风险之间的折中,而不是无碰撞保证。
- 未来的 bucketed prefix index 仍标为未完成,目标是把约 18 次读取降到 1–2 次,当前实现不能把该收益当作现状。
- README「Why this is interesting」:sorted 40-bit hashes in flash、~50 KB RAM、141,000+ domains fit in ~0.7 MB
- README「Why 40 bits?」:141k 约 0 次碰撞,537k 约 1 次碰撞
- README「Done / how it could grow」:Bucketed prefix index ⬜,约 18 次读取目标降至 1–2 次
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
不适合
我想让家庭和小型办公室里的客户端都通过 ESP32-C3 做 DNS,并依靠它拦截广告;如果设备短暂断电或客户端使用 DoH/DoT,这个方案还能满足约束吗?
适合读者: 维护家庭或小型办公室网络、希望把 ESP32-C3 作为唯一 DNS 服务器并拦截浏览器与智能家居流量的网络管理员
不适合把它作为唯一、不可绕过的 DNS 基础设施,因为设备离线会影响解析,而加密 DNS 能绕过它。
- 项目洞察明确指出 ESP32 是单点设备,断电、WiFi 中断、固件异常或 Flash 损坏都可能影响依赖它的 DNS;作为唯一 DNS 时需要回退方案。
- README 的 Use it 只要求客户端把 DNS 指向设备,或把它作为 secondary resolver,并不提供 DHCP 自动下发 DNS;DHCP server 仍是待实现功能。
- 项目洞察说明 DoH/DoT、硬编码 IP 或备用 DNS 会绕过基于 UDP DNS 的拦截;README 的实现路径也是命中后 sinkhole、未命中后转发。
- 因此它更适合家庭、小型办公室和实验网络中的辅助解析器,而不是强制所有终端经过的企业级 DNS 控制点。
- README「Done / how it could grow」:Act as the DHCP server 仍为 ⬜
- README「Use it」:Point a device's DNS at the C3's IP, or add it as a secondary resolver
- 项目洞察 usage_limitations:DoH/DoT、硬编码 IP、缓存或备用 DNS 可绕过拦截;ESP32 是单点设备
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
不适合
我只有 4 MB Flash、无 PSRAM 的 ESP32-C3 SuperMini,既想加载约 537k 域名,又想保留固件 OTA,这个项目适合吗?
适合读者: 使用 4 MB Flash、无 PSRAM 的 ESP32-C3 SuperMini,想在家庭网络中部署 537k 域名拦截并保留 WiFi OTA 的嵌入式开发者
不适合同时满足这两个目标,因为 4 MB Flash 的分区空间无法同时容纳最大列表和标准 OTA 布局。
- 项目确实针对无 PSRAM 的 ESP32-C3,40 位哈希把约 537k 域名放进 Flash,运行时约使用 50 KB RAM。
- 但项目洞察说明:启用双应用分区进行固件 OTA 后,blocklist 可用空间约 1.3 MB,容量约限制在 25 万域名;约 537k 域名需要单应用分区。
- 因此你需要在覆盖规模与远程固件维护之间取舍:保留 OTA 就接受较小列表,选择大列表则要保留 USB 恢复路径。
README 没有给出每种 PlatformIO 分区表的完整配置内容,不能据此判断自定义分区还能精确容纳多少域名。
- README「Why this is interesting」:537,000 domains、40-bit hashes、~50 KB RAM
- 项目洞察 common_pitfalls:4MB Flash 启用双应用 OTA 后约 1.3MB blocklist 空间、约 25 万域名
- 项目洞察 best_practices:最大 blocklist 需要选择更大分区并保留 USB 恢复路径
适合
我只有约 2 美元的无 PSRAM ESP32-C3,并希望直接插在路由器 USB 口上做家庭广告拦截;这个项目的部署体验是否比树莓派方案更合适?
适合读者: 熟悉 PlatformIO 的 DIY 爱好者,只有约 2 美元的 ESP32-C3、稳定 USB 供电和家庭路由器 USB 口,想避免树莓派或独立服务器
适合追求低成本、小体积和无需独立服务器的家庭部署,但它仍要求你具备 PlatformIO、USB 烧录和路由器 DNS 配置能力。
- README 明确定位为运行在约 2 美元 ESP32-C3、无需 PSRAM 的 Pi-hole-style DNS ad-blocker;USB-A 转 USB-C dongle 可直接插入多数路由器的备用 USB 口。
- 无法连接 WiFi 或未配置
secrets.h时,设备会启动C3-AdBlock-XXXX开放 AP 和 captive portal,首次联网不需要重新烧录。 - 项目包含 Web dashboard、统计、手动封禁、自定义域名、blocklist 更新和 firmware OTA,维护链路比每次拆机 USB 烧录更短。
- 代价是部署并非即插即用:README 仍要求把客户端 DNS 指向设备,而且稳定供电很重要;廉价或松动的 USB-C 转接头可能在 WiFi 发射时导致 brownout 重启。
- README 开头:Pi-hole-style DNS ad-blocker、$2 ESP32-C3、no PSRAM required
- README「Hardware」:USB-A → USB-C dongle 可直接插入多数路由器 USB 口;稳定 USB source
- README「WiFi setup」:无法连接时启动 `C3-AdBlock-XXXX` captive portal
- README「Done / how it could grow」:Web dashboard、OTA、scheduled remote blocklist pulls 已完成
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
视情况
我手上的不是主要测试目标 ESP32-C3,而是 4 MB Flash 的 Classic ESP32 DevKit/WROOM;我能否直接用这个项目,并把它作为家庭网络的 DNS?
适合读者: 熟悉 Arduino 和 PlatformIO、要把现有 Classic ESP32 DevKit / WROOM 4 MB 板改造成 DNS sinkhole 的嵌入式开发者
视情况,项目提供 Classic ESP32 构建支持,但主要测试目标仍是 ESP32-C3,且家庭 DNS 还取决于客户端是否真的把查询发给它。
- README 的 Hardware 章节明确写有 Classic ESP32(DevKit / WROOM,4 MB)也能构建,并给出
pio run -e esp32dev -t upload;同时注明这是社区贡献、仅 compile-tested,C3 才是 tested target。 - 架构支持命中域名返回 0.0.0.0,未命中请求转发到上游解析器,因此具备 DNS sinkhole 和普通解析的闭环。
- 使用时需要把客户端 DNS 指向 C3/ESP32 IP,或把设备作为主 DNS 后的 secondary resolver;DoH/DoT、硬编码 DNS 或备用解析路径可能绕过拦截。
README 没有说明 Classic ESP32 的实际查询延迟、最大列表规模或长期稳定性。
- README「Hardware」:Classic ESP32(DevKit / WROOM, 4 MB)也能构建;`pio run -e esp32dev -t upload`;C3 是 tested target
- README「Use it」:Point a device's DNS at the C3's IP, or add it as a secondary resolver
- README 顶部数据流:命中返回 0.0.0.0,未命中转发到 upstream resolver
pio run -e esp32dev -t upload
✨ 核心亮点
-
ESP32-C3无PSRAM也能运行537k域名列表
-
40-bit FNV-1a哈希占用约50KB RAM
-
flash二分查找约10ms完成DNS匹配
-
4MB闪存开启OTA后列表上限约250k
🔧 工程化
-
ESP32-C3通过UDP DNS sinkhole拦截域名并转发未命中查询
-
PlatformIO可刷写固件、blocklist.bin并通过WiFi OTA更新
-
http://c3adblock.local提供DNS统计、列表上传和Firmware OTA
⚠️ 风险
-
HTTP Basic Auth仅在明文HTTP :80上保护接口,不提供TLS
-
4MB闪存的双应用分区会把blocklist限制到约250k
-
40-bit哈希在537k域名规模预计出现1次碰撞并可能误拦截
-
secrets.h保留CHANGE_ME密码会让LAN接口使用公开凭据
👥 适合谁?
-
拥有4MB ESP32-C3 SuperMini并使用PlatformIO的家庭网络开发者
-
需要无PSRAM设备承载约100k默认列表的嵌入式开发者
-
希望用DNS secondary resolver部署轻量拦截器的网络用户