ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

如何彻底解决 DNS 转发错位?esp32-c3-adblock 超时与陈旧数据清理完整指南

如何彻底解决 DNS 转发错位?esp32-c3-adblock 超时与陈旧数据清理完整指南 如何彻底解决 DNS 转发错位esp32-c3-adblock 超时与陈旧数据清理完整指南【免费下载链接】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?featureshare项目地址: https://gitcode.com/GitHub_Trending/es/esp32-c3-adblock对于新手来说DNS 转发超时和陈旧数据清理听起来很抽象但 esp32-c3-adblock 用一套极简的可靠性设计把这两件事讲得明明白白。这个项目把 53.7 万个广告域名以 40 位 FNV-1a 哈希的形式存进 $2 的 ESP32-C3 闪存里查不到就转发给上游 DNS 并原样回传——而转发这个环节恰恰是小型 DNS 解析器最容易出错的地方。本文带你读懂它的上游转发可靠性设计1 秒超时截止、随机事务 ID、四重应答校验、陈旧数据先清空再转发。一、问题背景转发超时为什么会错位想象这样一个场景 设备收到设备 A 的查询转发给上游默认 Quad9 9.9.9.9可在编译时通过UPSTREAM_IP宏修改见 main.cpp上游响应太慢超时了设备放弃等待但那条迟到的响应随后到了还静静躺在 UDP 套接字里设备 B 发来一个新查询代码一读到数据就把 A 的旧答案回给了 B——从此所有应答整体错位一格。这正是项目 issue #10 记录的真实缺陷一次超时之后每个答案都偏移一位。修复思路写在 main.cpp 的注释里先清空陈旧数据再带着全新身份转发最后只接受完全匹配的应答。二、上游转发四步法超时截止 严格校验核心逻辑集中在 forwardUpstream() 这一个函数里拆开看就四步第一步清空套接字丢弃陈旧应答每次转发前固件先释放上一次可能读到一半的缓冲区然后循环读取并丢弃套接字里残留的所有数据报。这就是陈旧数据清理的第一道关口迟到的旧应答在到达的那一刻就被扔掉绝无机会被下一个客户端误领。第二步用随机事务 ID 重新署名DNS 报文开头 2 字节是事务 IDtransaction ID。客户端发来什么上游就应回什么这是匹配应答的基本依据。但 esp32-c3-adblock 不直接沿用客户端的 ID而是用esp_random()生成一个全新的随机 ID 盖在转发报文上客户端的原始 ID 只被悄悄记下来。这样即使上游返回了别的请求的应答也能被准确识别出来。第三步1 秒截止等待 四重匹配等待循环采用截止时间deadline而非重试次数总预算固定 1000 毫秒。期间每收到一个数据报都要连闯四道关卡✅来源地址必须来自上游的 IP 和 53 端口✅报文长度至少 12 字节的合法 DNS 头✅事务 ID必须与本次随机 ID 完全一致✅问题段把应答里的域名/类型字段与本次查询逐字节比对。任何一条不满足就丢弃继续等。全部通过后再把报文头 2 字节改回客户端原来的事务 ID才交还出去——客户端视角里一切与直接询问上游无异。第四步超时静默放弃客户端自行兜底1 秒内没等到合格应答函数返回 0设备不向客户端发任何回复。这是刻意的 fail-open放行策略让客户端的操作系统按自己的重试策略换下一个 DNS 服务器而不是收到一个可能错误的地址。宁可慢一拍不可错一格。三、陈旧数据的第二战场缓存与拦截表切换超时只是陈旧的一种。缓存过期、拦截表更新半途而废同样会给出过时答案。这个项目在两个层面做了清理设计。查询结果缓存只缓存不会变的东西闪存里的哈希表命中结果被放进一个 256 槽的直映射缓存以加速查询isBlockedHash()。但注释明确点出设计边界自定义域名不走缓存——它们随时可能通过网页后台增删若缓存了就会答出过期结果而闪存表只在整体重开文件时变化届时索引重建、缓存一并清空。哪些数据会变、变时谁负责清理写得清清楚楚。拦截表热替换先验证、再提交、失败回退无论是网页上传还是远程定时拉取可在后台配置 URL 和间隔见 main.cpp新拦截表都走同一套安全流程commitNewBlocklist()新文件先写到独立的/blocklist.new旧表保持服务校验通过大小非零、且是 5 字节哈希的整数倍才原子重命名上线校验失败则直接删除坏文件旧表原封不动继续工作。切换的空窗期numHashes为 0设备同样选择放行而非拦截避免拿半张表去判断流量。闪存分区预算则在 partitions.csv 中划分——双 OTA 布局下拦截表约可容纳 25 万个域名。四、普通用户视角这些设计意味着什么 ️转发不会串台家里任何一个设备查询拿到的都是属于自己的答案不会把邻居设备的缓存域名错配给你超时不伤体验上游卡顿时最多多等 1 秒之后静默跳过客户端自动兜底网页照开拦截表更新零风险远程自动更新build_blocklist.py 生成的blocklist.bin拉取失败或数据损坏时旧清单继续生效不会突然裸奔或误伤配置有门槛所有状态变更接口都需要认证参考 secrets.example.h避免局域网内他人篡改你的拦截策略。五、延伸阅读核心文件清单文件作用src/main.cpp全部固件逻辑DNS 转发、缓存、拦截表切换、网页后台src/main.cpp#L247-L271forwardUpstream()超时与陈旧数据清理的主角src/main.cpp#L142-L159查询缓存与失效边界tools/build_blocklist.py把域名清单构建成闪存哈希表tools/test_build_blocklist.py构建工具的测试partitions.csv闪存分区布局platformio.ini编译配置C3 / 经典 ESP32 双环境六、总结esp32-c3-adblock 的转发可靠性设计浓缩起来就三条经验对任何写网络服务的同学都适用超时后先清理现场——陈旧数据是错位之源丢弃比复用安全用可验证的身份而非先到先得——随机事务 ID 来源、长度、ID、问题段四重匹配让是不是我的答案不再有歧义数据更新走影子写入 校验 原子提交——失败回退旧版本永远不给系统留坏状态。一个 $2 的小芯片把这些工程细节做扎实了才能真正放进家里每一台设备 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?featureshare项目地址: https://gitcode.com/GitHub_Trending/es/esp32-c3-adblock创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表