DNS协议指南:从报文格式到安全加密与 K8s 实战

📌 本文亮点:从 DNS 报文字节级拆解到迭代/递归解析全流程,从 dig 高级用法到 DoH/DoT/DoQ 加密方案,从 DNSSEC 信任链到 K8s CoreDNS 服务发现,附 7 个实战排障场景!

前言

每次你在浏览器输入 www.example.com,背后都有一场精密的分布式协作------你的请求从本机出发,经过递归解析器、根域名服务器、TLD 服务器、权威服务器,最终拿到一个 IP 地址。整个过程通常在 几十毫秒内完成。

但当你遇到"域名解析偶尔超时"、"修改 DNS 记录后迟迟不生效"、"SERVFAIL 但不知道为什么"这些问题时,如果不理解 DNS 的底层机制,就只能靠运气排障。

本文从协议报文 出发,系统梳理 DNS 的完整知识体系------报文格式、解析流程、记录类型、加密方案、安全机制,最终落到 dig/tcpdump 实战和 K8s CoreDNS 排障。


一、DNS 核心概念

1.1 DNS 是什么

DNS(Domain Name System)是一个层次化、分布式的命名系统,核心功能是将人类可读的域名转换为机器可用的 IP 地址。

DNS 本质上是一个分布式数据库

  • 没有单点:全球 13 组根服务器 + 数千台 TLD/权威服务器
  • 层次化 :根 → TLD(.com)→ 权威(example.com),逐级授权
  • 缓存驱动:每层都有 TTL 缓存,减少重复查询

1.2 DNS 服务器类型

类型 说明 示例
根服务器 13 组逻辑实例,知道所有 TLD 的位置 a.root-servers.net ~ m.root-servers.net
TLD 服务器 管理顶级域名下的授权信息 .com.org.cn
权威服务器 存储域名的实际记录(A、MX 等) ns1.example.com
递归解析器 代替客户端完成整个解析链 8.8.8.81.1.1.1
转发解析器 将查询转发给上游递归解析器 企业内网 DNS

💡 递归解析器是客户端的"代理",它代替客户端走完整个迭代查询链。客户端只需问递归解析器一次。


二、DNS 解析全流程

2.1 一次完整解析的路径

以解析 www.example.com 的 A 记录为例:

复制代码
┌──────────┐  ①  ┌───────────┐  ②  ┌──────────┐  ③  ┌──────────┐  ④  ┌──────────┐
│  客户端   │────▶│ 递归解析器 │────▶│  根服务器 │────▶│ TLD 服务器│────▶│ 权威服务器│
│(Stub)    │◀────│(Recursive)│◀────│(Root)    │◀────│(.com)    │◀────│(example) │
└──────────┘  ⑨  └───────────┘  ⑧  └──────────┘  ⑤  └──────────┘  ⑥  └──────────┘
               │               │               │               │
               │    ⑦ 缓存结果  │               │    返回授权    │    返回 A 记录
               │    直接应答    │               │    NS 记录     │    93.184.216.34

详细步骤:

  1. 客户端向递归解析器发送查询:www.example.com A
  2. 递归解析器检查缓存,未命中则向根服务器查询
  3. 根服务器返回 .com TLD 的 NS 记录(授权)
  4. 递归解析器向 .com TLD 服务器查询
  5. TLD 服务器返回 example.com 的 NS 记录
  6. 递归解析器向 example.com 权威服务器查询
  7. 权威服务器返回 A 记录:93.184.216.34
  8. 递归解析器缓存结果(按 TTL)
  9. 递归解析器将结果返回客户端

2.2 递归查询 vs 迭代查询

对比项 递归查询 迭代查询
谁负责走完整个链 解析器 客户端自己
典型场景 客户端 → 递归解析器 递归解析器 → 根/TLD/权威
返回结果 最终答案 要么答案,要么"去问谁"
RD 标志 RD=1(请求递归) RD=0
RA 标志 RA=1(支持递归) RA=0

💡 客户端对递归解析器发的是递归查询 (RD=1),递归解析器对根/TLD/权威发的是迭代查询(RD=0)。

2.3 递归查询 vs 迭代查询详解

生活中的类比
  • 递归查询 = 你去图书馆问管理员"帮我找一本关于 DNS 的书",管理员自己跑遍所有书架,最终把书递给你
  • 迭代查询 = 你去图书馆问管理员"DNS 的书在哪?",管理员说"去三楼科技区找",你跑到三楼再问,三楼说"去第 7 排",你跑到第 7 排自己找到
逐步过程对照
步骤 方向 查询类型 发生了什么
客户端 → 递归解析器 递归 "帮我查 www.example.com 的 A 记录"
递归解析器 → 根服务器 迭代 "你知道 www.example.com 吗?"
根服务器 → 递归解析器 迭代响应 "我不知道,但 .com 的 NS 是这些,你去问它"
递归解析器 → TLD 服务器 迭代 "你知道 www.example.com 吗?"
TLD → 递归解析器 迭代响应 "我不知道,但 example.com 的 NS 是这些,你去问它"
递归解析器 → 权威服务器 迭代 "你知道 www.example.com 吗?"
权威 → 递归解析器 迭代响应 "我知道,A 记录是 93.184.216.34"
递归解析器 → 客户端 递归响应 "你要的答案是 93.184.216.34"
用 dig 验证两种查询

递归查询(默认行为,RD=1):

bash 复制代码
dig www.example.com @8.8.8.8

# ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
# ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
#                    ^^ ^^
#                    RD=1 RA=1 → 递归查询,解析器支持递归

迭代查询跟踪+trace 模拟递归解析器的迭代过程):

bash 复制代码
dig +trace www.example.com

# ;; NS SECTION:
# .           518400  IN  NS  a.root-servers.net.    ← 第1跳:根
# ;; Received 1261 bytes from 198.97.190.53#53

# com.        172800  IN  NS  a.gtld-servers.net.   ← 第2跳:.com TLD
# ;; Received 1221 bytes from 192.5.6.30#53

# example.com.  172800  IN  NS  ns1.example.com.    ← 第3跳:权威
# ;; Received 123 bytes from 192.5.6.30#53

# www.example.com. 3600 IN A 93.184.216.34          ← 最终答案

💡 dig +trace 展示的就是递归解析器内部的迭代过程------逐级从根→TLD→权威获取 referral,最终拿到答案。

2.4 生产环境用哪种查询方式

生产环境两种都用,各司其职:

复制代码
┌────────┐  递归查询   ┌──────────┐  迭代查询   ┌────────┐
│        │  (RD=1)    │          │  (RD=0)    │        │
│ 客户端  │──────────▶│ 递归解析器 │──────────▶│ 权威服务器│
│        │◀──────────│(8.8.8.8) │◀──────────│        │
└────────┘  最终答案   └──────────┘  referral   └────────┘

为什么这样分工

环节 方式 原因
客户端 → 递归解析器 递归 客户端(浏览器/应用)不想逐级追问,只要最终答案
递归解析器 → 根/TLD/权威 迭代 权威服务器不能替客户端跑全链路,否则全球 13 组根服务器扛不住

生产环境的递归解析器部署

方案 说明 适用场景
Unbound 开源递归解析器,支持 DNSSEC 验证 企业内网 DNS、安全要求高
BIND(递归模式) 既可做权威也可做递归 传统企业、混合部署
CoreDNS K8s 集群内递归 + 服务发现 K8s 环境
公共 DNS 8.8.8.8 / 1.1.1.1 小型/无内网 DNS 的环境

⚠️ 权威服务器不允许递归查询 。如果你对权威服务器发递归查询(RD=1),它会返回 REFUSED------这是安全策略,防止权威服务器被滥用为开放递归器。

验证:权威服务器拒绝递归

bash 复制代码
# 对权威服务器发递归查询 → REFUSED
dig www.example.com @ns1.example.com
# ;; status: REFUSED

# 对权威服务器发迭代查询(+norecurse)→ 正常返回
dig +norecurse www.example.com @ns1.example.com
# ;; status: NOERROR
# ;; AUTHORITY SECTION:
# example.com. 172800 IN NS ns1.example.com.   ← 返回授权信息

💡 一句话总结:客户端用递归(省事),解析器用迭代(分散压力)------这就是 DNS 设计的分层协作模型,生产环境没有任何一个角色只做一种查询。

2.5 缓存与 TTL

DNS 的性能核心是缓存,每条记录都带有 TTL(Time To Live):

  • 递归解析器缓存:按 TTL 倒计时,过期后重新查询
  • 操作系统缓存 :如 Windows ipconfig /displaydns
  • 浏览器缓存 :Chrome chrome://net-internals/#dns
  • 应用缓存 :JVM 默认缓存成功的 DNS 解析永久 (需配置 networkaddress.cache.ttl

⚠️ "DNS 传播延迟"不是真的"传播",而是旧缓存还没过期。修改记录前应先降低 TTL,等旧 TTL 过期后再改值。


三、DNS 报文格式

3.1 报文整体结构

一个 DNS 报文由 5 个段组成:

复制代码
+------------+
|  Header    |   12 字节,固定长度
+------------+
|  Question  |   查询的问题
+------------+
|  Answer    |   应答的资源记录
+------------+
|  Authority |   权威服务器的资源记录
+------------+
| Additional |   附加信息(如 Glue 记录)
+------------+

3.2 Header 格式(12 字节)

复制代码
                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

各字段说明:

字段 位数 说明
ID 16 事务 ID,响应必须与请求相同
QR 1 0=查询,1=响应
Opcode 4 0=标准查询,5=动态更新
AA 1 权威应答标志
TC 1 截断标志(超过 UDP 512 字节限制)
RD 1 期望递归(Recursion Desired)
RA 1 支持递归(Recursion Available)
Z 3 保留(其中 AD=认证数据,CD=禁用检查)
RCODE 4 响应码(0=NOERROR, 2=SERVFAIL, 3=NXDOMAIN, 5=REFUSED)
QDCOUNT 16 问题数
ANCOUNT 16 应答记录数
NSCOUNT 16 权威记录数
ARCOUNT 16 附加记录数

3.3 域名编码(标签压缩)

DNS 中的域名使用长度前缀标签编码:

text 复制代码
www.example.com 编码为:
\x03www\x07example\x03com\x00
  │     │        │     │
  │     │        │     └─ 根标签(0 结尾)
  │     │        └─ "com"(长度 3)
  │     └─ "example"(长度 7)
  └─ "www"(长度 3)

💡 DNS 还支持指针压缩:重复的域名后缀用 2 字节指针替代(高 2 位=11,低 14 位=偏移量),大幅减少报文大小。

3.4 报文实例:抓一个 DNS 查询

bash 复制代码
# 抓取 DNS 查询
tcpdump -i eth0 -n -vvv -c 2 'udp port 53'
text 复制代码
14:42:12.989067 IP 10.0.2.15.11008 > 192.168.1.1.53: 17791+ [1au] A? www.example.com. (50)
14:42:12.989655 IP 192.168.1.1.53 > 10.0.2.15.11008: 17791* 1/1/2 A 93.184.216.34 (99)

解读:

字段 查询行 响应行
事务 ID 17791 17791(与请求匹配)
标志 +(RD=1) *(AA=1,权威应答)
记录数 [1au](1 条 Additional) 1/1/2(1 Answer / 1 Authority / 2 Additional)
查询类型 A?(A 记录查询) A 93.184.216.34(A 记录应答)

四、DNS 记录类型

4.1 核心记录类型

类型 全称 说明 示例
A Address IPv4 地址 example.com. IN A 93.184.216.34
AAAA IPv6 Address IPv6 地址 example.com. IN AAAA 2606:2800:220:1:...
CNAME Canonical Name 域名别名 blog.example.com. IN CNAME pages.cdn.net.
MX Mail Exchanger 邮件服务器(带优先级) example.com. IN MX 10 mail.example.com.
NS Name Server 域名权威服务器 example.com. IN NS ns1.example.com.
SOA Start of Authority 区域授权起始(管理元数据) example.com. IN SOA ns1 admin 20260101 ...
PTR Pointer 反向解析(IP → 域名) 34.216.184.93.in-addr.arpa. IN PTR example.com.
TXT Text 文本记录(SPF、验证等) example.com. IN TXT "v=spf1 mx -all"
SRV Service 服务发现(端口+主机) _sip._tcp.example.com. IN SRV 10 5 5060 sip.example.com.
CAA Certification Authority 证书授权限制 example.com. IN CAA 0 issue "letsencrypt.org"

4.2 SOA 记录详解

SOA 是每个区域的第一条记录,包含管理元数据:

text 复制代码
example.com. IN SOA ns1.example.com. hostmaster.example.com. (
    2026061401   ; Serial(序列号,YYYYMMDDnn 格式)
    3600         ; Refresh(从服务器检查主服务器的时间间隔)
    600          ; Retry(刷新失败后重试间隔)
    604800       ; Expire(从服务器数据过期时间)
    300          ; Minimum / Negative Cache TTL(否定缓存时间)
)

💡 SOA 的 Minimum 字段决定了 NXDOMAIN 的缓存时间。当你删除一条记录后,客户端和递归解析器会在 Negative Cache TTL 内继续返回 NXDOMAIN。

4.3 CNAME 的限制

  • CNAME 不能与其他记录共存:一个名称如果设置了 CNAME,就不能再有 A、MX、TXT 等记录
  • CNAME 不能指向另一个 CNAME:虽然技术上可行,但增加了解析延迟
  • MX/NS 不能指向 CNAME:RFC 要求 MX/NS 目标必须是 A/AAAA 记录

4.4 DNSSEC 专用记录

类型 说明
DNSKEY 区域公钥(ZSK 签名密钥 + KSK 密钥签名密钥)
RRSIG 资源记录集的数字签名
DS 委派签名者(父区域持有的子区域 KSK 哈希)
NSEC / NSEC3 不存在证明(证明"这个名字不存在")

五、EDNS(0) 扩展机制

传统 DNS 限制 UDP 报文不超过 512 字节,DNSSEC 签名的记录远超此限制。EDNS(0)(RFC 6891)解决了这个问题:

5.1 EDNS 核心功能

功能 说明
UDP 载荷协商 客户端通告"我能接收 4096 字节",超出则回退 TCP
DO 标志 DNSSEC OK,客户端请求 DNSSEC 响应
扩展 RCODE 超过 4 位的错误码
客户端子网 传递用户真实子网,提升 CDN 地理路由精度

5.2 EDNS 在报文中的位置

EDNS 通过 Additional 段的 OPT 伪记录传递:

text 复制代码
; 查询中的 OPT 记录
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;                 ^^          ^^^^^^^^
;                 DO=1        UDP 缓冲区 4096 字节

⚠️ 如果中间设备(防火墙/负载均衡器)不识别 OPT 记录而丢弃 EDNS 查询,会导致 DNSSEC 解析失败。这是生产环境 DNS 故障的常见原因。


六、DNS 加密方案

传统 DNS 查询以明文传输,任何人都能看到你查询了哪些域名。现代 DNS 提供了三种加密方案:

6.1 三种加密方案对比

方案 端口 传输层 握手开销 典型使用场景
DoT 853 TLS 1-RTT OS 级(Android 私有 DNS、systemd-resolved)
DoH 443 TLS + HTTP/2 1-RTT(或 0-RTT 恢复) 浏览器级(Chrome、Firefox、Edge)
DoQ 853 QUIC/TLS 1.3 0-RTT 递归↔权威;新兴客户端支持
复制代码
┌────────────────────────────────────────────────────────────┐
│  安全性分层                                                 │
│                                                            │
│  DNSSEC  → 数据真实性(签名验证,防篡改)不加密              │
│  DoT/DoH → 传输机密性(TLS 加密,防窃听)不验证数据来源      │
│  两者互补:DNSSEC 防篡改 + DoH 防窃听 = 完整安全链          │
└────────────────────────────────────────────────────────────┘

6.2 DoH 实战:curl 查询

Cloudflare DoH(JSON 格式)

bash 复制代码
# 查询 A 记录(JSON 响应,人类可读)
curl -s -H "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=example.com&type=A" | jq

响应示例:

json 复制代码
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": false,
  "CD": false,
  "Question": [
    { "name": "example.com.", "type": 1 }
  ],
  "Answer": [
    {
      "name": "example.com.",
      "type": 1,
      "TTL": 1726,
      "data": "93.184.216.34"
    }
  ]
}

Google DoH(JSON 格式)

bash 复制代码
# 查询 A 记录
curl -s "https://dns.google/resolve?name=example.com&type=A" | jq

# 带 DNSSEC 数据
curl -s "https://dns.google/resolve?name=example.com&type=A&do=1" | jq

RFC 8484 二进制格式(POST)

bash 复制代码
# Wire format POST 查询
echo -n "q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" | base64 -d | \
  curl -s --data-binary @- \
  -H "content-type: application/dns-message" \
  https://cloudflare-dns.com/dns-query | hexdump -C

curl 原生 DoH 支持(7.62+)

bash 复制代码
# 使用 DoH 解析域名后访问网站
curl --doh-url https://cloudflare-dns.com/dns-query https://www.example.com

6.3 DNS 响应码(RCODE)

RCODE 名称 含义 排障思路
0 NOERROR 成功 正常
1 FORMERR 查询格式错误 检查查询工具版本
2 SERVFAIL 服务器失败 通常是 DNSSEC 验证失败,dig +cd 绕过
3 NXDOMAIN 域名不存在 确认域名拼写、检查是否被删除
4 NOTIMP 未实现 服务器不支持此查询类型
5 REFUSED 拒绝查询 ACL 策略限制,或查询了不允许递归的服务器

七、DNSSEC:DNS 安全扩展

7.1 DNSSEC 解决什么问题

DNSSEC 解决的是数据真实性和完整性问题------防止 DNS 响应被篡改(如 DNS 缓存投毒)。

⚠️ DNSSEC 不加密查询。它只保证"你收到的数据确实是权威服务器发布的",但任何人都能看到你查了什么。加密是 DoT/DoH/DoQ 的事。

7.2 DNSSEC 工作原理

复制代码
┌───────────────────────────────────────────────────────────────┐
│  DNSSEC 信任链                                                │
│                                                               │
│  根区域 KSK(信任锚点,预装在解析器中)                        │
│    │                                                          │
│    ├─ 签名 .com 区域的 DS 记录(父持有子的 KSK 哈希)         │
│    │                                                          │
│    ├─ .com 区域 KSK                                           │
│    │   ├─ 签名 .com 区域的 DS 记录                             │
│    │   │                                                      │
│    │   ├─ example.com 区域 KSK                                 │
│    │   │   ├─ 签名 example.com 的 ZSK                          │
│    │   │   │   ├─ 签名 A 记录 → RRSIG                          │
│    │   │   │   ├─ 签名 MX 记录 → RRSIG                         │
│    │   │   │   └─ 签名 NS 记录 → RRSIG                         │
│    │   │   └─ DNSKEY(KSK + ZSK 公钥)                         │
│    │   └─ DS 记录(父区域持有子区域 KSK 的哈希)                │
│    └─ ...                                                     │
└───────────────────────────────────────────────────────────────┘

关键角色:

  • ZSK(Zone Signing Key):签名区域内的记录,经常轮换
  • KSK(Key Signing Key):签名 ZSK,很少轮换,其哈希由父区域持有
  • DS(Delegation Signer):父区域存储的子区域 KSK 哈希,链接信任链
  • RRSIG:附加在每个 RRset 上的签名

7.3 DNSSEC 验证标志

标志 方向 含义
AD(Authenticated Data) 响应中 递归解析器设置,表示 Answer/Authority 段已通过 DNSSEC 验证
CD(Checking Disabled) 查询中 客户端请求解析器跳过验证,返回原始数据(调试用)
DO(DNSSEC OK) 查询 EDNS 中 客户端声明"我想要 DNSSEC 响应"

7.4 NSEC vs NSEC3

两者都用于证明"某个名称不存在":

机制 原理 隐私 缺点
NSEC 返回"前一个存在名称 → 下一个存在名称" 差(可枚举所有名称) 区域遍历攻击
NSEC3 返回哈希后的名称范围 好(哈希后无法直接枚举) 计算开销大

八、dig 命令高级用法

8.1 常用标志

bash 复制代码
# 只显示 IP 地址
dig +short www.example.com

# 跟踪完整授权链(从根开始)
dig +trace www.example.com

# 请求 DNSSEC 记录
dig +dnssec www.example.com

# 禁用 DNSSEC 验证(绕过 SERVFAIL)
dig +cd www.example.com

# 只显示 Answer 段
dig +noall +answer www.example.com

# 强制 TCP 传输
dig +tcp example.com

# 设置 EDNS 缓冲区大小
dig +bufsize=1232 example.com

# 显示查询统计
dig +stats example.com

8.2 查询特定记录类型

bash 复制代码
dig example.com MX          # 邮件服务器
dig example.com TXT         # 文本记录
dig example.com NS          # 权威服务器
dig example.com SOA         # 区域管理信息
dig example.com CAA         # 证书授权
dig example.com SRV         # 服务发现
dig example.com ANY         # 所有记录(大多数服务器已禁用)

8.3 区域传送

bash 复制代码
# 完整区域传送(通常被禁止,除非授权)
dig AXFR example.com @ns1.example.com

# 增量区域传送
dig IXFR=2026010101 example.com @ns1.example.com

8.4 反向解析

bash 复制代码
# IPv4 反向解析
dig -x 8.8.8.8

# IPv6 反向解析
dig -x 2001:4860:4860::8888

8.5 批量查询与传播检查

bash 复制代码
# 检查多个递归解析器的解析结果(验证传播)
for resolver in 8.8.8.8 1.1.1.1 9.9.9.9; do
    echo "=== $resolver ==="
    dig @$resolver +short api.example.com
done

# 查询权威服务器(跳过缓存)
AUTH_NS=$(dig NS example.com +short | head -1)
dig @$AUTH_NS www.example.com

九、DNS 排障实战场景

9.1 SERVFAIL 排查

SERVFAIL 最常见的原因是 DNSSEC 验证失败

bash 复制代码
# 第一步:正常查询返回 SERVFAIL
dig www.example.com @8.8.8.8
# ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL

# 第二步:用 +cd 绕过 DNSSEC 验证
dig +cd www.example.com @8.8.8.8
# 如果 +cd 能返回结果 → DNSSEC 是原因

# 第三步:验证 DNSSEC 信任链
dig +trace +dnssec www.example.com

# 第四步:用 delv 逐步验证
delv +vtrace www.example.com

9.2 NXDOMAIN 排查

bash 复制代码
# 检查是否是缓存导致的延迟(查看 Authority 段的 SOA)
dig deleted-record.example.com

# 查看否定缓存 TTL(SOA 的 Minimum 字段)
dig example.com SOA +short
# ns1 admin 20260101 3600 900 604800 300
#                                     ^^^ 否定缓存 300 秒

# 直接查询权威服务器(跳过缓存)
AUTH_NS=$(dig NS example.com +short | head -1)
dig @$AUTH_NS target.example.com

9.3 TTL 过期 / 传播延迟

bash 复制代码
# 查看剩余 TTL(从缓存中倒计时)
dig api.example.com +noall +answer
# api.example.com.    1423    IN    A    192.168.1.100
#                     ^^^^ 剩余缓存秒数

# 变更记录的标准流程:
# 1. 变更前 24-48 小时,将 TTL 降至 300
# 2. 等待旧 TTL 过期
# 3. 修改记录值
# 4. 验证传播
# 5. 恢复 TTL

9.4 Split-Horizon DNS 检测

bash 复制代码
# 内部解析器返回内网 IP
dig internal-app.example.com
# 10.0.1.50

# 外部解析器返回公网 IP
dig @8.8.8.8 internal-app.example.com
# 203.0.113.10

9.5 Wireshark 过滤器速查

text 复制代码
dns                                # 所有 DNS 流量
dns.flags.response == 0            # 仅查询
dns.flags.response == 1            # 仅响应
dns.flags.rcode == 0               # NOERROR
dns.flags.rcode == 2               # SERVFAIL
dns.flags.rcode == 3               # NXDOMAIN
dns.qry.type == 1                  # A 记录
dns.qry.type == 28                 # AAAA 记录
dns.qry.name contains "example.com"
dns.time > 0.1                     # 慢响应(>100ms)

十、DNS Zone 文件格式

10.1 完整示例

bind 复制代码
$ORIGIN example.com.
$TTL 3600    ; 默认 TTL:1 小时

@   IN  SOA  ns1.example.com.  hostmaster.example.com. (
            2026061401   ; Serial(YYYYMMDDnn)
            3600         ; Refresh:1 小时
            600          ; Retry:10 分钟
            604800       ; Expire:1 周
            300 )        ; Minimum / Negative Cache:5 分钟

; 域名服务器
@       IN  NS   ns1.example.com.
@       IN  NS   ns2.example.net.

; Glue 记录(NS 的 A/AAAA)
ns1     IN  A    192.0.2.1
ns1     IN  AAAA 2001:db8::1
ns2     IN  A    198.51.100.1

; 邮件交换
@       IN  MX   10  mail.example.com.
@       IN  MX   20  backup-mail.example.net.

; A 和 AAAA 记录
@       IN  A    203.0.113.50
@       IN  AAAA 2001:db8:1::50
www     IN  A    203.0.113.50
mail    IN  A    203.0.113.20
api     IN  A    203.0.113.100

; CNAME 别名
blog    IN  CNAME  pages.cdn.example.net.

; TXT 记录(SPF、验证)
@       IN  TXT   "v=spf1 mx -all"
@       IN  TXT   "google-site-verification=abc123"

; SRV 记录
_sip._tcp   IN  SRV  10  5  5060  sipserver.example.com.

; CAA 记录
@       IN  CAA   0 issue "letsencrypt.org"
@       IN  CAA   0 issuewild ";"

10.2 Zone 文件关键规则

规则 说明
末尾句点 ns1.example.com. 是绝对域名;缺少句点则加上 $ORIGIN 后缀
CNAME 限制 有 CNAME 的名称不能有其他记录
SOA 邮箱 hostmaster.example.com. 对应 hostmaster@example.com
Serial 格式 YYYYMMDDnn,每天最多改 99 次
TTL 继承 无显式 TTL 的记录使用 $TTL 默认值

10.3 验证 Zone 文件

bash 复制代码
# BIND 验证工具
named-checkzone example.com /var/named/example.com.zone

# NSD 验证工具
nsd-checkzone example.com example.com.zone

十一、DNS 常见攻击与防御

11.1 DNS 放大攻击

原理:攻击者伪造源 IP(受害者的 IP),向开放解析器发送小查询,解析器返回大响应淹没受害者。

bash 复制代码
# 检测异常 DNS 响应流量
tcpdump -i eth0 -n 'udp port 53 and udp[10] & 0x80 != 0' | wc -l

# ANY 查询产生极大响应(常被滥用)
dig ANY isc.org @open-resolver

防御:关闭开放递归、限速、部署 BCP38 反欺骗过滤。

11.2 DNS 缓存投毒

原理:攻击者猜中事务 ID 和源端口,向递归解析器注入伪造响应。

bash 复制代码
# 对比多个解析器的结果(不一致则可能被投毒)
for r in 8.8.8.8 1.1.1.1 9.9.9.9; do
    echo -n "$r: "; dig @$r victim.com +short
done

# 用 DNSSEC 验证(投毒的响应无法通过签名验证)
dig +dnssec victim.com

防御:启用 DNSSEC、源端口随机化、0x20 大写随机化。

11.3 DNS 隧道

特征:大量随机子域名查询、超长子域、TXT 记录滥用。

bash 复制代码
# 从 pcap 提取 DNS 查询域名
tshark -r dns.pcap -Y "dns.qry.name" -T fields -e dns.qry.name > queries.txt

# 检测超长子域名(合法域名通常 15-30 字符)
awk '{print length, $0}' queries.txt | sort -rn | head -20

# 检测 Base64/Hex 模式
grep -E '^[A-Za-z0-9+/=]{20,}\.' queries.txt

十二、Kubernetes DNS 服务发现

12.1 CoreDNS 架构

CoreDNS 以 Deployment 运行在 kube-system 命名空间,通过 kube-dns Service 暴露 ClusterIP,所有 Pod 的 /etc/resolv.conf 指向该 IP。

bash 复制代码
# 查看 CoreDNS Pod
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 查看 Corefile 配置
kubectl get configmap coredns -n kube-system -o yaml

# 查看 Pod 的 resolv.conf
kubectl exec -it my-pod -- cat /etc/resolv.conf
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

12.2 默认 Corefile 解读

text 复制代码
.:53 {
    errors          ; 错误日志
    health {        ; 健康检查
        lameduck 5s
    }
    ready           ; 就绪探针
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure           ; Pod DNS 模式
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    prometheus :9153   ; Prometheus 指标
    forward . /etc/resolv.conf   ; 外部查询转发
    cache 30           ; 缓存 30 秒
    loop               ; 检测转发环路
    reload             ; 自动重载配置
    loadbalance        ; 随机化 A/AAAA 记录顺序
}

12.3 K8s DNS 记录格式

资源 DNS 格式 记录类型
ClusterIP Service my-svc.my-ns.svc.cluster.local A → ClusterIP
Headless Service my-svc.my-ns.svc.cluster.local A → Pod IP 列表
ExternalName Service my-svc.my-ns.svc.cluster.local CNAME → 外部域名
SRV(命名端口) _port._proto.my-svc.my-ns.svc.cluster.local SRV
Pod(带 hostname) hostname.subdomain.my-ns.svc.cluster.local A
Pod(IP 格式) 10-244-1-5.my-ns.pod.cluster.local A

12.4 K8s DNS 排障

CoreDNS 环路崩溃

bash 复制代码
# 原因:节点 /etc/resolv.conf 指向 127.0.0.53(systemd-resolved)
# 修复:kubelet --resolv-conf 指向 /run/systemd/resolve/resolv.conf

ndots:5 性能问题

bash 复制代码
# ndots:5 导致 'api.github.com' 触发 4 次 search domain 查询后才查绝对域名
# 修复:对外部流量为主的 Pod 设置 ndots:2
apiVersion: v1
kind: Pod
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"

启用 CoreDNS 查询日志

bash 复制代码
# 编辑 Corefile,添加 log 插件
kubectl -n kube-system edit configmap coredns
# .:53 {
#     log    ← 添加此行
#     errors
#     ...
# }

自定义 Stub 域(企业内网 DNS)

text 复制代码
corp.internal:53 {
    errors
    cache 30
    forward . 10.150.0.1    ; 转发到企业内网 DNS
}

十三、DNS 学习路线

复制代码
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  入门     │───▶│  进阶     │───▶│  高级     │───▶│  安全     │───▶│  K8s     │
│          │    │          │    │          │    │          │    │          │
│ 解析流程  │    │ dig 排障  │    │ 报文格式  │    │ DNSSEC   │    │ CoreDNS  │
│ 记录类型  │    │ Zone 文件 │    │ EDNS     │    │ DoH/DoT  │    │ 服务发现  │
│ 缓存 TTL  │    │ 反向解析  │    │ 抓包分析  │    │ 攻击防御  │    │ 自定义配置│
└──────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘

总结

本文核心要点:

  1. DNS 是层次化分布式数据库:根 → TLD → 权威,逐级授权,缓存驱动
  2. 递归 vs 迭代是核心概念:客户端对解析器是递归(RD=1),解析器对权威是迭代
  3. 报文格式决定排障能力:理解 Header 标志位(QR/AA/TC/RD/RA/RCODE)才能读懂 tcpdump 输出
  4. DNSSEC 防篡改,DoH/DoT 防窃听:两者互补,缺一不可
  5. SERVFAIL 先试 dig +cd:90% 的 SERVFAIL 是 DNSSEC 验证失败
  6. K8s DNS 的 ndots:5 是性能杀手 :外部流量密集的 Pod 应设置 ndots:2

📌 参考文档


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

相关推荐
千寻girling3 小时前
记录第一次学习 Docker
学习·docker·容器
迷糊小面包4 小时前
Docker Hadopp集群版部署搭建及常规问题解疑
运维·docker·容器
HavenlonLabs5 小时前
重塑链上未来的隐形基石:长期主义下的生态演进
大数据·人工智能·安全·区块链
烁3475 小时前
Docker
运维·docker·容器
网络中的夜鹰6 小时前
轩辕镜像一键安装Docker和Docker Compose脚本
运维·docker·容器
lihongbao806 小时前
kuboard v3创建用户分配命名空间
kubernetes·kuboard
其实防守也摸鱼6 小时前
软件安全与漏洞--Windows底层原理与软件逆向工程基础
linux·网络·数据库·算法·安全·安全架构·软件安全与漏洞
杨先生哦8 小时前
2026 热端攻防:AI 驱动 Web 前端安全全景透析
前端·笔记·安全·web安全
江湖有缘9 小时前
Docker部署HamsterBase Tasks任务管理工具
运维·docker·容器