Cheburcheck 俄罗斯封锁检测工具 Reporter 深度剖析:1000 并发百万域名白名单采集设计完整指南
Cheburcheck 俄罗斯封锁检测工具 Reporter 深度剖析:1000 并发百万域名白名单采集设计完整指南
Cheburcheck 是一个用于检查域名和 IP 地址是否在俄罗斯被封锁的开源服务。它的 Reporter 组件通过 1000 并发探针,在短时间内完成百万级域名的封锁并行采集,并自动沉淀出"确认可访问"的域名白名单,是这个封锁检测工具背后的核心数据来源。
🔍 核心原理:如何用 SNI 判断一个域名是否被"封锁"
Cheburcheck Reporter 的探测思路不是真正访问目标网站,而是做 SNI 封锁检测:
- 自定义 DNS 解析器把所有域名都指向同一个测试服务器 IP(默认
5.78.7.195); - 发起 TLS 握手时,域名会写在 SNI(Server Name Indication)字段中;
- 如果该 SNI 命中 DPI(深度包检测)黑名单,连接会被重置或超时;
- 测试服务器对任意 SNI 都会返回至少 64KB 的数据,程序用
Range: bytes=0-65536只取前 64KB——读满 64KB 才算可访问,读不满即判定被封锁。
自定义解析器实现得非常短小精悍,忽略任何域名、永远返回测试 IP:resolver.rs
每次扫描结果被归为四类证据:Ok(可访问)、Blocked(封锁)、ConnectError(连接失败)、Error(未知错误),定义见 lib.rs。
📦 百万域名列表:编译期直接"烧"进二进制
Reporter 以 Tranco 全球域名热度榜单作为扫描清单,它不在运行时下载,而是在编译阶段完成:
- 默认拉取 1,000,000 个域名,同时生成 64KB 随机垃圾数据写入
OUT_DIR; - 运行时通过
include_str!把列表直接嵌进可执行文件。
这样做的好处是:部署后不依赖任何网络下载、无需维护列表文件,且列表版本随版本号一起"冻结",扫描结果可复现。完整逻辑见 build.rs。
⚙️ 1000 并发采集:Semaphore + FuturesUnordered 实战
main.rs 的主循环是整个程序最核心的部分,只有二十几行代码:
- 并发控制:
tokio::sync::Semaphore(1000)保证最多 1000 个域名同时探测,避免文件描述符被打满; - 无阻塞收集:任务 future 统一放入
FuturesUnordered,谁先完成谁先被收集统计,没有"等最慢的那个"问题; - 优雅退出:第一次 Ctrl-C 停止派发新任务、等存量任务收尾后保存结果;第二次按下才强制退出;
- 进度可视:
indicatif进度条实时显示进度、ETA 与吞吐速度。
⚠️ 一个实用提醒:高并发依赖系统的 open files 限制,程序启动时会用 getdtablesize() 检查 ulimit -n 并给出警告(main.rs);随包提供的 systemd 服务则直接配置了 LimitNOFILE=16384。
🔁 重试与超时设计:降低误报率的关键
网络抖动很容易把正常域名"冤判"为封锁。Reporter 用几个精巧的策略压制误报:
| 策略 | 参数 | 作用 |
|---|---|---|
| 每域名重试 | -r, --retry-count(默认 2 次) |
恢复瞬时超时 |
| 读取超时随次数线性增长 | 5s → 10s | 给重试留出余量 |
| 发送 64KB 垃圾数据 | -x, --tx |
触发 TLS DPI,区分"从一开始就拦" |
| plain-HTTP 对照 | -H, --http |
判断是 SNI 封锁还是纯网络问题 |
超时递增由 retry_read_timeout 计算,并有单元测试保证第 3 次尝试等待 15 秒(main.rs)。单个域名的完整探测与重试逻辑在 check_target 中;扫描结束后的统计聚合与 CSV 导出由 counter.rs 的 Counter 完成。
📊 上报即白名单:MsgPack + COPY 批量入库 + 物化视图
白名单不是单次扫描的"拍脑袋"结果,而是一条完整的上报链路:
- Reporter 把结果用 MsgPack 序列化后 POST 到 Agency 端点(main.rs);
- 服务端在同一事务内:写入
reports记录本次扫描参数(版本、并发数、超时等),再用COPY ... FROM STDIN把百万行结果批量灌入report_row,比逐行 INSERT 快一个数量级; REFRESH MATERIALIZED VIEW CONCURRENTLY在线无锁刷新whitelist物化视图。
白名单的判定规则是"多数投票":只取主 Reporter 最近 5 份报告,某域名可访问次数过半才进入白名单(optimizations.sql)。这一设计让偶发的网络波动不会把域名错误地踢出或拉入白名单。上报接收的完整实现见 agency.rs。
⏰ 三步部署:用 systemd 定时器全自动采集
项目自带 Debian 打包与 systemd 单元,cargo deb 构建后即可开箱使用:
sudo apt install cheburchecker_*.deb
echo "AGENCY_KEY=你的密钥" | sudo tee /etc/default/cheburchecker
装完即获得两套互不冲突的自动调度:
cheburchecker.100k.timer:每 6 小时(06:00 / 12:00 / 18:00 UTC)检查 100,000 个域名;cheburchecker.1kk.timer:每天检查 1,000,000 个域名。
本地 CSV 报告归档在 /var/log/cheburchecker/,可用 journalctl -u cheburchecker@100000.service 查看运行日志。服务与定时器定义见 cheburchecker@.service 和 cheburchecker.1kk.timer,参数总表见 reporter/README.md。
总结
| 设计点 | 解决的问题 |
|---|---|
| SNI 探测 + 自定义解析器 | 不访问真实站点就能检测 DPI 封锁 |
| 编译期内嵌百万域名清单 | 运行零网络依赖、结果可复现 |
| Semaphore(1000) + FuturesUnordered | 高并发且不空等,短时间扫完百万域名 |
| 递增超时重试 + 垃圾数据对照 | 显著降低误报率 |
| MsgPack 上报 + COPY 批量入库 + 物化视图 | 百万行秒级入库,白名单在线更新 |
| systemd 双定时器 | 零人工介入的持续白名单采集 |
Cheburcheck Reporter 用不到 500 行 Rust 代码(src/ 目录)打通了"并行采集 → 上报入库 → 白名单生成"全链路,是学习 Rust 高并发网络工具设计的绝佳范本。
