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):

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 模拟递归解析器的迭代过程):

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(递归模式)既可做权威也可做递归传统企业、混合部署
CoreDNSK8s 集群内递归 + 服务发现K8s 环境
公共 DNS8.8.8.8 / 1.1.1.1小型/无内网 DNS 的环境

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

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

# 对权威服务器发递归查询 → 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                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

各字段说明:

字段位数说明
ID16事务 ID,响应必须与请求相同
QR10=查询,1=响应
Opcode40=标准查询,5=动态更新
AA1权威应答标志
TC1截断标志(超过 UDP 512 字节限制)
RD1期望递归(Recursion Desired)
RA1支持递归(Recursion Available)
Z3保留(其中 AD=认证数据,CD=禁用检查)
RCODE4响应码(0=NOERROR, 2=SERVFAIL, 3=NXDOMAIN, 5=REFUSED)
QDCOUNT16问题数
ANCOUNT16应答记录数
NSCOUNT16权威记录数
ARCOUNT16附加记录数

3.3 域名编码(标签压缩)

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

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

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

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

# 抓取 DNS 查询
tcpdump -i eth0 -n -vvv -c 2 'udp port 53'
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)

解读:

字段查询行响应行
事务 ID1779117791(与请求匹配)
标志+(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 核心记录类型

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

4.2 SOA 记录详解

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

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 伪记录传递:

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

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


六、DNS 加密方案

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

6.1 三种加密方案对比

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

6.2 DoH 实战:curl 查询

Cloudflare DoH(JSON 格式)

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

响应示例:

{
  "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 格式)

# 查询 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)

# 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+)

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

6.3 DNS 响应码(RCODE)

RCODE名称含义排障思路
0NOERROR成功正常
1FORMERR查询格式错误检查查询工具版本
2SERVFAIL服务器失败通常是 DNSSEC 验证失败,dig +cd 绕过
3NXDOMAIN域名不存在确认域名拼写、检查是否被删除
4NOTIMP未实现服务器不支持此查询类型
5REFUSED拒绝查询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 常用标志

# 只显示 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 查询特定记录类型

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 区域传送

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

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

8.4 反向解析

# IPv4 反向解析
dig -x 8.8.8.8

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

8.5 批量查询与传播检查

# 检查多个递归解析器的解析结果(验证传播)
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 验证失败

# 第一步:正常查询返回 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 排查

# 检查是否是缓存导致的延迟(查看 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 过期 / 传播延迟

# 查看剩余 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 检测

# 内部解析器返回内网 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 过滤器速查

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 完整示例

$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 文件

# BIND 验证工具
named-checkzone example.com /var/named/example.com.zone

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

十一、DNS 常见攻击与防御

11.1 DNS 放大攻击

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

# 检测异常 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 和源端口,向递归解析器注入伪造响应。

# 对比多个解析器的结果(不一致则可能被投毒)
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 记录滥用。

# 从 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。

# 查看 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 解读

.: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 Servicemy-svc.my-ns.svc.cluster.localA → ClusterIP
Headless Servicemy-svc.my-ns.svc.cluster.localA → Pod IP 列表
ExternalName Servicemy-svc.my-ns.svc.cluster.localCNAME → 外部域名
SRV(命名端口)_port._proto.my-svc.my-ns.svc.cluster.localSRV
Pod(带 hostname)hostname.subdomain.my-ns.svc.cluster.localA
Pod(IP 格式)10-244-1-5.my-ns.pod.cluster.localA

12.4 K8s DNS 排障

CoreDNS 环路崩溃

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

ndots:5 性能问题

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

启用 CoreDNS 查询日志

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

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

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 版权协议,转载请附上原文出处链接及本声明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值