本页目录
DNS 协议与解析
互联网的"电话簿"——从根服务器到递归解析器到权威服务器,一次 DNS 查询可能触发数十次委派追踪。edns0、anycast、负缓存,这些机制让 DNS 在日均万亿次查询下仍然可用。
概述
DNS 是互联网的"电话簿"——将人类可读的域名翻译为 IP 地址。设计于 1983 年(RFC 882/883),分布式和层次化的架构使其可以扩展到互联网规模:从 root 到 TLD 到 authoritative,每一层只负责自己的命名空间。递归解析器做"繁重工作"——替 stub client 完成从 root 到 answer 的全过程。DNS 最初是无安全设计的协议(UDP 明文),后来的 DNSSEC 和加密传输(DoT/DoH/DoQ)都在修补这个缺憾。
DNS 查询流程
三种查询类型:
- Recursive (RD=1): resolver 替客户端全程递归 (stub → recursive)
- Iterative: 一次返回 referral 或 answer (recursive → authoritative)
- Inverse: PTR 查询 (IP → name, 极少用)
DNS Wire Format
DNS Message (TCP or UDP):
Header (12 bytes):
Transaction ID (2B): 随机, 匹配 request ⇔ response
Flags (2B):
QR (bit 0): 0=Query, 1=Response
OPCODE (bits 1-4): 0=Standard, 1=Inverse, 2=Status, 4=Notify, 5=Update
AA (bit 5): Authoritative Answer
TC (bit 6): Truncated (use TCP)
RD (bit 7): Recursion Desired
RA (bit 8): Recursion Available
Z (bits 9-11): 0 (reserved)
RCODE (bits 12-15): 0=NoError, 1=FormErr, 2=SrvFail, 3=NXDomain, 5=Refused
QDCOUNT (2B): Questions count
ANCOUNT (2B): Answers count
NSCOUNT (2B): Authority records count
ARCOUNT (2B): Additional records count
Question Section (variable):
QNAME: label format (见下)
QTYPE (2B): 1=A, 28=AAAA, 5=CNAME, 15=MX, 2=NS, 6=SOA, 33=SRV, ...
QCLASS (2B): 1=IN (Internet)
Answer/Authority/Additional Sections (variable):
每个 RR:
NAME: label format (通常 compressed — pointer to previous name)
TYPE (2B)
CLASS (2B): 1=IN
TTL (4B): cache 有效期 (秒)
RDLENGTH (2B): RDATA 长度
RDATA: type-specific
Label Format 与 Compression
Label encoding:
[length 1B][label data ...] → 长度 + 数据, 每 label 独立
最后一个 label: length=0 (root, 空 label)
例: www.example.com → 0x03 'w' 'w' 'w' 0x07 'e' 'x' 'a' 'm' 'p' 'l' 'e' 0x03 'c' 'o' 'm' 0x00
DNS Compression (节省空间):
高 2 bits of length byte = 11 → 这是 pointer (不是 label!)
pointer = 低 14 bits of offset (from DNS message start)
例: 0xC0 0x0C → 指向 offset 12 (第一个 question 的 QNAME)
这允许在同一消息中重复引用之前出现的 domain name
→ "example.com" 出现在 QNAME, A record 的 NAME, NS record 的 RDATA → 三次引用 → 省 ~12+12+12 = 36 bytes
关键 Record Types
A (type 1): RDATA = 4-byte IPv4 address
AAAA (type 28): RDATA = 16-byte IPv6 address
CNAME (type 5): RDATA = canonical name (label format) — 别名解析
→ 限制: CNAME 不能与其他类型共存 (除了 RRSIG/NSEC)
即: 如果 www.example.com 是 CNAME, 它不能同时有 A record
MX (type 15): RDATA = preference (2B) + exchange (label format)
→ 优先级: 低 preference = 高优先级
SOA (type 6): RDATA = mname + rname + serial + refresh + retry + expire + minimum TTL
→ zone 的权威信息: serial 用于 zone transfer 版本比较
NS (type 2): RDATA = nameserver (label format) — 授权此 zone 的 nameserver
SRV (type 33): RDATA = priority + weight + port + target
→ _service._proto.name → 目标 host:port
例: _sip._tcp.example.com SRV 10 60 5060 sipserver.example.com
PTR (type 12): RDATA = name (label format) — reverse lookup (IP → name)
→ in-addr.arpa for IPv4, ip6.arpa for IPv6
TXT (type 16): RDATA = one or more text strings (length-prefixed)
→ SPF, DKIM, DMARC, verification tokens
CAA (type 257): RDATA = flags + tag + value
→ 限制哪些 CA 可以为此 domain 签发证书
→ 例: 0 issue "letsencrypt.org" → 只有 Let's Encrypt 能签
EDNS0 (RFC 6891)
传统 DNS 限制: UDP payload 最大 512B → 大型应答 (DNSSEC RRSIG) 需要 TCP fallback
EDNS0: 在 Additional section 加 OPT pseudo-RR:
NAME=0 (root), TYPE=41 (OPT), CLASS=UDP payload size, TTL=flags+RCODE
UDP payload size: 通告接收方能处理的最大 UDP 响应 (通常 1232 or 4096)
→ 减少 TCP fallback 次数
DNSSEC OK (DO bit): client 支持 DNSSEC → server 应该附带 RRSIG
flags: DNSSEC OK (DO bit 15)
AFXR (Zone Transfer)
AXFR (full zone transfer):
常用于: primary → secondary nameserver 同步
TCP connection (zone transfer 可能 >512B):
secondary: AXFR request (type 252, class IN) → primary
primary: 返回 zone 中所有 RRs (SOA ... SOA, 头尾两个 SOA)
IXFR (incremental zone transfer, RFC 1995):
只传输变化 (基于 SOA serial)
参考
- RFC: 1034, 1035, 6891, 3596 (AAAA), 2782 (SRV), 6844 (CAA)
- 工具:
dig +trace,drill,kdig,delv,tcpdump -nn port 53 - 源码: glibc
resolv/,systemd-resolved
Keywords: DNS, A/AAAA/MX/NS/SOA/SRV/CNAME/TXT/CAA, recursive resolver, EDNS0, label compression, zone transfer