☰
esp32-c3-adblock 自定义上游 DNS:一行编译参数切换全网解析出口
2026/10/20 1:47:33 网站建设 项目流程

esp32-c3-adblock 自定义上游 DNS:一行编译参数切换全网解析出口

【免费下载链接】esp32-c3-adblockPi-hole-class DNS ad-blocker on a $2 ESP32-C3 (no PSRAM): 537k domains as 40-bit FNV-1a hashes in flash, binary-searched. UDP DNS sinkhole + web dashboard. https://youtube.com/shorts/RaxszOUMi8E?feature=share项目地址: https://gitcode.com/GitHub_Trending/es/esp32-c3-adblock

esp32-c3-adblock 是一个跑在约 2 美元 ESP32-C3 上的 Pi-hole 式 DNS 广告拦截器。本文给出它自定义上游 DNS 配置的完整做法:在 platformio.ini 里加一行定义,重新烧录后,整网的解析出口就从默认的 Quad9 换成你指定的任意解析器。

一行改动换解析器:速览

  • 改哪里:platformio.ini 中[env:c3]的build_flags,追加一行-DUPSTREAM_IP=1, 1, 1, 1即指向 Cloudflare。
  • 为什么生效:src/main.cpp 里的默认上游(9.9.9.9:53)被#ifndef包着,编译时定义了同名宏就会自动覆盖默认值,源码保持原样。
  • 怎么生效:pio run -t upload走 USB 烧录,或把固件传到 Web 控制台做 OTA 升级。
  • 怎么确认:两条dig命令——广告域名应返回0.0.0.0,正常域名应返回真实 IP。
  • 副作用:无。拦截发生在转发之前,新上游只经手没被拦下的查询。

原理速读:先拦截,后转发

每条 DNS 查询先经过 C3 本地这一关:把域名(连同各级父级后缀逐一)算成 FNV-1a 40 位哈希,再在 Flash 里存的约 53.7 万个哈希上做二分查找。命中就立刻回0.0.0.0掐掉;未命中才把查询转给UPSTREAM_IP指定的解析器,并把它的应答原样传回客户端。

DNS 查询进入 │ ├── 域名命中 Flash 哈希表 ──▶ 直接回 0.0.0.0(拦截,上游完全不参与) │ └── 未命中 ──▶ 转发给上游解析器 ──▶ 把上游应答传回客户端 UPSTREAM_IP : UPSTREAM_PORT

把 C3 理解成前台:广告流量在门口就被拒之门外,只有"正常访客"才会被转交给指定的接待方——也就是上游。因此上游的速度和政策决定了全网的浏览体验,而拦截效果则与它无关。

上游解析器怎么选:四个常见候选

解析器地址取向适合谁
Quad9(项目默认)9.9.9.9偏安全,自带 DGA 恶意域名与 DNS 隧道封堵默认就多一层恶意域名过滤
Cloudflare1.1.1.1速度与隐私见长,不记录客户端 IP要响应快、日志负担轻
Cloudflare 家庭版1.1.1.2在 1.1.1.1 之上加成人内容过滤有青少年的家庭
Google8.8.8.8全球节点多,延迟普遍低网络环境多变、求稳

⚠️ 共同前提:上游地址必须能被 C3 直接访问。家用宽带下,上述公共解析器均可直连,不涉及端口转发。

实操:修改 UPSTREAM_IP 并烧录固件

给 build_flags 追加一行编译定义

  • 改什么:一个-DUPSTREAM_IP宏。
  • 在哪改:platformio.ini 的[env:c3]段。
  • 改完预期:编译通过,.pio/build/c3/下生成新的firmware.bin。

实际改动只有一行,其余保持原样:

[env:c3] board = esp32-c3-devkitm-1 build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 -DUPSTREAM_IP=1, 1, 1, 1 ; 上游指向 Cloudflare

想切回 Quad9 就写9, 9, 9, 9;上游跑在非标准端口(如 5353)时再加一行-DUPSTREAM_PORT=5353——端口默认是 53,多数情况不用写。

两条烧录路径:USB 直刷与控制台 OTA

  • 做什么:把新固件写进 C3。
  • 在哪做:项目根目录执行命令,或 Web 控制台(http://c3adblock.local)的Firmware → OTA update区域。
  • 做完预期:设备重启后回到控制台界面,随后的 dig 查询已走新上游。

USB 路径,在项目根目录执行:

pio run -t upload

OTA 路径适合设备已在线、不想拔线的场景:打开控制台,输入 Web 密码,把刚构建出的.pio/build/c3/firmware.bin拖进Firmware → OTA update区域,设备校验通过后自行重启进入新镜像。

用两条 dig 命令确认切换

在能访问 C3 的机器上依次执行(把 IP 换成 C3 实际地址):

dig @<c3-ip> doubleclick.net # 预期 0.0.0.0:广告被拦下 dig @<c3-ip> github.com # 预期真实 IP:由新上游转发解析

第一条命中哈希表,根本不会触及上游;第二条能返回真实地址,才说明转发链路确实走了 1.1.1.1。顺手刷新控制台,观察 allowed(放行)计数在涨,是转发存活的旁证。

验证与排错:预期输出和异常对照

观察到的现象可能原因排查方向
doubleclick.net返回真实 IP 而非 0.0.0.0拦截列表为空或损坏(换列表期间设备会 fail-open,全部直转)看控制台域名计数是否为 0,重新上传blocklist.bin
github.com超时无应答上游不可达或端口写错,转发 1 秒超时后放弃确认 C3 到上游的网络;核对-DUPSTREAM_PORT设置
github.com返回 0.0.0.0该域名本身也在拦截列表,或客户端缓存了旧应答换其他域名再测;清掉客户端 DNS 缓存
dig @<c3-ip>连不上C3 掉线或 IP 变了从路由器或控制台查当前 IP,确认设备在网

若以上都不像,接串口看启动日志(pio device monitor),里面会打印 WiFi 状态和拦截列表域名数,定位最快。

延伸:配网、列表更新与相关文件

上游换了,下面三套机制照常运转:

  • 拦截与转发解耦:命中哈希表的查询在门口就被拒,到不了上游;转发链路还会丢弃过期应答、严格按事务 ID 匹配,防止多个客户端的应答串包。
  • WiFi 配网保留:首次连不上网时设备放出热点C3-AdBlock-XXXX,手机连上后在强制门户选网、输密码即可;之后换网络点控制台的Forget WiFi,或上电按住 BOOT 键重新进配网,不用重刷。
  • 拦截列表走独立链路:tools/build_blocklist.py 生成blocklist.bin,经控制台Blocklist → Upload上传,或配置Remote auto-update让设备按小时定期自行拉取,与上游 DNS 互不干涉。

想往下看的话:主逻辑在 src/main.cpp(上游定义就在文件开头),仪表盘界面在 src/page.h,完整文档与构建细节见 README.md。

整网的解析出口,说到底就是这一个宏——编译参数落定之后,剩下的交给控制台和 OTA 就好。

【免费下载链接】esp32-c3-adblockPi-hole-class DNS ad-blocker on a $2 ESP32-C3 (no PSRAM): 537k domains as 40-bit FNV-1a hashes in flash, binary-searched. UDP DNS sinkhole + web dashboard. https://youtube.com/shorts/RaxszOUMi8E?feature=share项目地址: https://gitcode.com/GitHub_Trending/es/esp32-c3-adblock

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询