“域名打不开”第一反应通常是:
- 换 8.8.8.8 试一下
- ping 一下看 IP 对不对
- 清缓存、等 TTL
这是排障,不是检测。
生产业务要的是:在用户投诉前,系统自己证明“解析被污染了”。
域名污染的本质不是“解析错一次”,而是:
- 递归缓存被投毒
- 链路中间人抢答
- 权威侧被改(账号泄露/注册商被控)
- 合规管控返回假 NXDOMAIN/黑洞 IP
本文给一套可落地的“域名污染持续检测平台”:
多递归器交叉 + 全球拨测 + 权威直查 + DNSSEC 验证 + 基线比对 + 告警收敛,把一次手工排查变成 7×24 的解析健康面。
一、先定义:什么叫“检测到污染”,别误判 CDN 调度
同域名不同 DNS 返回不同 IP,不一定是污染:
- CDN 按地理/ECS 返回不同边缘节点(正常)
- 智能解析按运营商分线(正常)
- 灰度权重轮询(正常)
- Anycast 同 IP 多地域(正常)
- KKCE 域名污染检测
污染判定要满足“异常信号组合”:
- 权威直查结果稳定,但部分递归器长期返回非预期 IP 集合
- 异常 IP 特征:内网地址、127.0.0.0/8、0.0.0.0、黑洞段、陌生 AS
- 特定地区/运营商集中异常,换网络即恢复
- TTL 异常短(几秒级)或响应抢答无真实链路
- DNSSEC 验证失败(有签名却 AD 位不置位)
差异是线索,一致性异常才是证据。
二、检测平台整体架构
text
[探测源](全球拨测节点 + 内网探针) │ 定时查询目标域名 ▼ [探测执行层] ├─ 多公共递归:8.8.8.8 / 1.1.1.1 / 9.9.9.9 / 223.5.5.5 ├─ 多运营商 LocalDNS:电信/联通/移动/海外 ├─ 权威直查:@ns 查 A/AAAA/CNAME/NS ├─ DoH/DoT 通道:绕明文 UDP └─ +trace:根→TLD→权威逐跳 ▼ [比对引擎] ├─ 权威基线(受控预期 IP 集合) ├─ 历史基线(滚动 7 天解析指纹) ├─ CDN 白名单(边缘段聚合,不逐 IP 比) └─ AS/地理归属校验 ▼ [判定与告警] 异常分级 → 告警 → 自动取证快照 → 工单
核心原则:
- 不信任单一递归器
- 不信任单次结果
- 用“分布 + 时间 + 签名”三维交叉
三、探测执行:每条命令都是数据点
1. 多递归交叉(最基础)
bash
domain=api.example.com for r in 8.8.8.8 1.1.1.1 9.9.9.9 223.5.5.5; do echo "== $r ==" dig @$r $domain A +short | sort done
判定逻辑:
- 公共递归结果聚成 1 类、运营商递归聚成另 1 类 → 区域链路污染嫌疑
- 某递归长期返回内网/黑洞 IP → 该递归缓存投毒
- 权威直查正确、递归错 → 问题在递归/链路
2. 权威直查兜底
bash
auth_ns=$(dig $domain NS +short | head -1) dig @$auth_ns $domain A +norecurse +noall +answer
权威对、递归错 = 中间层问题
权威也错 = 去查注册商/NS 是否被改、DNSSEC 是否失效
3. 逐跳追踪
bash
dig +trace $domain
看哪一跳开始变答案:
- 根/TLD 就返回假 A → 严重中间人/根镜像异常
- 权威前正常、递归返回假 → 链路抢答
4. DNSSEC 验证
bash
dig +dnssec $domain A # 正常:flags 带 ad ;RRSIG 存在 # 失败:SERVFAIL 或 ad 位缺失
DNSSEC 不是防污染万能药,但能区分:
- “响应被改” → 验证失败
- “只是调度差异” → 验证通过
5. TTL 与响应特征
bash
dig $domain +noall +answer
异常信号:
- 权威 TTL 300,递归返回 TTL 一直 0–5s(伪造响应)
- 同查询多次结果随机跳
- 返回 127.0.0.1 / 0.0.0.0 / 10.x 给公网名
四、比对引擎:把“像不像污染”变成分数
别写死 if ip != 预期: 告警,会炸。
用分层判定:
text
1. 精确匹配:非 CDN 域名,IP 集合必须 ∈ 基线 2. 前缀匹配:CDN 域名,IP 必须 ∈ 厂商网段(Cloudflare/阿里/腾讯/云厂商) 3. AS 匹配:解析 IP 的 AS 归属是否在允许清单 4. 地理匹配:海外名不应解析到纯内网/异常国家 5. 签名匹配:DNSSEC 域名必须 ad=1 6. 时间维度:单点偶发不告警,区域持续 3 周期才升级
伪代码:
python
score = 0 if not ip_set.issubset(baseline): score += 2 if any_ip_in_blackhole_range: score += 3 if dnssec_expected and not ad: score += 3 if ttl_anomaly: score += 1 if region_consistent_anomaly(3x): score += 2 if score >= 5: alert("DNS_POLLUTION_SUSPECTED", domain, region)
五、全球拨测:单台机器没资格下结论
本地笔记本查出来“不对”,可能是你家 ISP 问题。
生产检测要:
- 国内:电信/联通/移动/教育网多省节点
- 海外:美西/美东/法兰/东京/新加坡/香港
- 协议:UDP53 / DoH / DoT 各探一次
- 频率:核心域名 30s,普通域名 5min
开源/自研思路:
text
拨测 agent(轻量 Go 二进制) → 上报结果到中心 → 中心做区域聚合 → 出“污染热力图”:哪个国家/运营商/递归器异常
判定样例:
text
海外 40 节点全对,国内 3 省运营商返回 127.0.0.1 → 判定:国内区域链路污染,不是全球篡改
六、基线管理:没基线就没有“异常”
1. 受控基线(Git 里声明)
yaml
domains: api.example.com: expected_ip_prefix: - "203.0.113." - "198.51.100." allow_cdn_as: [13335, 37963, 45102] dnssec: true admin.internal.example: public_resolvable: false # 公网解析到任何 IP 都算异常
2. 动态基线(滚动学习)
- 过去 7 天解析 IP 集合(去重)
- 正常波动窗口:CDN 边缘 IP 池
- 新 IP 首次出现 → 低优先级观察
- 新 IP + 黑洞特征 → 高优先级告警
3. 变更关联
解析变更走 GitOps,发布单号写入基线:
- 主动变更期不告警
- 无变更单却出现新 IP → 直接升级
七、告警收敛:别把运维群刷死
分级:
- P3:单节点单次异常,自动复探 3 次
- P2:单运营商区域持续 5min 异常
- P1:权威直查也被改 / DNSSEC 验证失败 / 多省同时黑洞
- P0:交易/登录域名解析到陌生 AS
收敛规则:
- 同域名同区域 5min 内合并一条
- 自动附取证快照(dig 输出、AS、TTL、trace 摘要)
- 自动跑
hosts 绑定真实 IP探活,区分“污染”还是“IP 被封”
八、应急取证:告警同时留证据包
每次命中自动落盘:
json
{ "ts": "2026-11-01T02:10:00Z", "domain": "api.example.com", "region": "CN-Telecom", "resolver": "202.96.128.86", "bad_ips": ["127.0.0.1"], "auth_ips": ["203.0.113.10"], "dnssec": false, "ttl": 3, "trace": "root ok, tld ok, recursor spoof", "baseline_rev": "v102" }
留证目的:
- 后续投诉/合规用
- 区分“攻击”还是“运营商误拦”
- 回滚后对比是否收敛
九、防御闭环:检测完必须能缓解
检测平台不是只报警,要联动:
- 终端侧:App 切 DoH/HTTPDNS(绕过污染递归)
- 服务端:开 DNSSEC(让验证型递归拒假答案)
- 业务侧:关键域名备独立接入(CNAME 到另一家 DNS 提供商)
- 账号侧:注册商锁 + 2FA + NS 变更告警
- 网络侧:Anycast DNS 多供应商,避免单 NS 被劫持
十、最小落地清单
- [ ] 核心域名清单 + 预期 IP/AS 基线(Git 管理)
- [ ] 多递归器交叉探测脚本(4 公共 + 多运营商)
- [ ] 权威直查 + +trace + DNSSEC 校验
- [ ] 全球拨测 agent(国内多省 + 海外多区)
- [ ] 比对引擎:精确/前缀/AS/签名四维评分
- [ ] 动态基线 + 变更单关联(主动变更静默)
- [ ] 告警分级 + 取证快照自动落库
- [ ] 应急联动:DoH/HTTPDNS/DNSSEC/多权威 NS
十一、什么别用检测平台干
- 拿单次 dig 差异直接发 P0(CDN 调度误杀)
- 只测 UDP 53 不测 DoH(漏掉链路层结论)
- 基线写死单 IP(CDN 一扩就告警风暴)
- 不区分“污染”和“IP 封禁”(hosts 绑 IP 验证一步不能省)
- 只测公网不测内部解析(内部名被投毒更致命)
十二、总结
域名污染检测在 SRE 体系里最被低估的价值,不是“排障快”,而是:
让解析层具备“自证清白”的能力。
用户说“打不开”,你不用猜;
系统已经知道:
- 哪国哪运营商哪递归器在返回假答案
- 权威对不对、签名过没过、TTL 正不正常
- 是链路抢答,还是账号被改,还是合规黑洞
dig 是听诊器,
拨测平台是 CT;
一次排查救一个域名,
持续检测救一整年业务。
DNS 是互联网最老、最裸、最易被骗的一层。
你没法让它不被攻击,
但你可以让它每次被攻击,
都当场留下指纹。