DNS协议技术指南 (RFC 1035)
本文档是RFC 1035的详细技术指南,包含消息格式、资源记录类型、实用示例和工具使用说明。如需查看RFC官方章节翻译,请参考各章节文档。
文档信息
- RFC编号: 1035
- 标题: Domain Names - Implementation and Specification
- 标题(中文): 域名 - 实现和规范
- 发布日期: 1987年11月
- 作者: P. Mockapetris (USC/Information Sciences Institute)
- 状态: INTERNET STANDARD (STD 13)
摘要
本RFC定义了DNS (Domain Name System)的实现细节,包括消息格式、资源记录格式、以及名称服务器和解析器的行为规范。本文档与RFC 1034 (DNS概念和设施)配套,RFC 1034定义概念,而本文档定义具体实现。
核心概念: RFC 1035是DNS的实现规范,定义了消息格式、记录类型和实现细节。
与RFC 1034的关系
RFC 1034 (概念) RFC 1035 (实现)
───────────────── ─────────────────
✓ DNS是什么 → ✓ 消息格式
✓ 域名结构 → ✓ 资源记录格式
✓ 名称服务器架构 → ✓ 解析算法
✓ 缓存策略 → ✓ 压缩机制
✓ 查询类型 → ✓ 协议细节
建议:
先读RFC 1034理解概念
再读RFC 1035了解实现
DNS消息格式
消息结构
所有DNS消息使用相同格式:
+---------------------+
| Header | 12字节,固定
+---------------------+
| Question | 查询部分(可变长度)
+---------------------+
| Answer | 回答部分(可变长度)
+---------------------+
| Authority | 授权部分(可变长度)
+---------------------+
| Additional | 附加部分(可变长度)
+---------------------+
Header格式
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 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
总长度: 12字节
字段详解
ID (16位)
用途: 匹配查询和响应
范围: 0-65535
使用: 客户端随机生成,服务器原样返回
示例:
Query: ID = 12345
Response: ID = 12345 (相同)
QR (1位) - Query/Response
0 = Query (查询)
1 = Response (响应)
示例:
客户端发送: QR=0
服务器回复: QR=1
Opcode (4位) - 操作码
0 = QUERY (标准查询)
1 = IQUERY (反向查询,已废弃)
2 = STATUS (服务器状态查询)
3-15 = 保留
常用: Opcode=0 (标准查询)
AA (1位) - Authoritative Answer
权威回答标志
0 = 非权威回答 (来自缓存)
1 = 权威回答 (来自权威服务器)
示例:
查询 example.com A记录
→ example.com的NS返回: AA=1
→ 缓存服务器返回: AA=0
TC (1位) - Truncation
截断标志
0 = 未截断
1 = 已截断 (消息超过512字节,UDP)
处理:
if TC=1:
切换到TCP重新查询
RD (1位) - Recursion Desired
期望递归查询
0 = 不要递归 (仅查询本地)
1 = 请递归查询
客户端设置:
通常设为1,要求DNS服务器递归查询
RA (1位) - Recursion Available
支持递归查询
0 = 不支持递归
1 = 支持递归
服务器响应:
if 服务器支持递归: RA=1
else: RA=0
Z (3位) - Reserved
保留字段,必须为0
注意:
现代扩展使用部分Z位
DNSSEC使用其中一位(AD, CD)
RCODE (4位) - Response Code
响应代码
| RCODE | 含义 | 说明 |
|-------|------|------|
| 0 | NOERROR | 成功 |
| 1 | FORMERR | 格式错误 |
| 2 | SERVFAIL | 服务器失败 |
| 3 | NXDOMAIN | 域名不存在 |
| 4 | NOTIMP | 不支持 |
| 5 | REFUSED | 拒绝查询 |
常见错误:
NXDOMAIN (3) = 域名不存在
SERVFAIL (2) = 服务器临时故障
QDCOUNT (16位)
Question部分的条目数
通常为1
ANCOUNT (16位)
Answer部分的资源记录数
NSCOUNT (16位)
Authority部分的资源记录数
ARCOUNT (16位)
Additional部分的资源记录数
Question Section格式
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ QNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
QNAME: 要查询的域名 (可变长度)
QTYPE: 查询类型 (16位)
QCLASS: 查询类 (16位,通常为1=IN)
QNAME编码
域名使用标签序列编码:
域名: www.example.com
编码:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|03| w w w |07| e x a m p l e |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|02| c o m |00|
+--+--+--+--+--+
格式:
- 每个标签前面是长度 (1字节)
- 标签内容 (ASCII字符)
- 以0结束
示例:
"www.example.com" =
3 "www" 7 "example" 3 "com" 0
根域名: 0 (单个0字节)
QTYPE (查询类型)
常用类型:
| 值 | 类型 | 说明 |
|----|------|------|
| 1 | A | IPv4地址 |
| 2 | NS | 名称服务器 |
| 5 | CNAME | 规范名称 (别名) |
| 6 | SOA | 授权开始 |
| 12 | PTR | 指针 (反向解析) |
| 15 | MX | 邮件交换 |
| 16 | TXT | 文本记录 |
| 28 | AAAA | IPv6地址 |
| 255 | ANY | 所有记录 (已不推荐) |
示例:
查询 example.com 的IPv4地址:
QTYPE = 1 (A记录)
QCLASS (查询类)
| 值 | 类 | 说明 |
|----|-----|------|
| 1 | IN | Internet (互联网) |
| 2 | CS | CSNET (已废弃) |
| 3 | CH | CHAOS |
| 4 | HS | Hesiod |
| 255 | ANY | 任何类 |
通常使用: QCLASS = 1 (IN)
Answer/Authority/Additional格式
资源记录 (Resource Record, RR) 格式:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ NAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| CLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TTL |
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| RDLENGTH |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/ RDATA /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
NAME: 域名
TYPE: 记录类型
CLASS: 记录类 (通常为1=IN)
TTL: 生存时间 (秒)
RDLENGTH: RDATA长度
RDATA: 记录数据 (格式取决于TYPE)
资源记录类型详解
A记录 - IPv4地址
TYPE = 1
RDLENGTH = 4 (字节)
RDATA = 32位IPv4地址
示例:
NAME: example.com
TYPE: A (1)
CLASS: IN (1)
TTL: 3600
RDLENGTH: 4
RDATA: 93.184.216.34
编码 (RDATA):
93.184.216.34 → 0x5DB8D822
NS记录 - 名称服务器
TYPE = 2
RDATA = 名称服务器的域名
示例:
NAME: example.com
TYPE: NS (2)
TTL: 86400
RDATA: ns1.example.com
含义: example.com的权威服务器是ns1.example.com
CNAME记录 - 别名
TYPE = 5
RDATA = 规范名称
示例:
NAME: www.example.com
TYPE: CNAME (5)
TTL: 3600
RDATA: example.com
含义: www.example.com是example.com的别名
查询流程:
查询 www.example.com A
→ 返回 CNAME example.com
→ 继续查询 example.com A
→ 返回 93.184.216.34
SOA记录 - 授权开始
TYPE = 6
RDATA格式:
MNAME: 主名称服务器
RNAME: 负责人邮箱
SERIAL: 序列号
REFRESH: 刷新间隔
RETRY: 重试间隔
EXPIRE: 过期时间
MINIMUM: 最小TTL
示例:
NAME: example.com
TYPE: SOA (6)
TTL: 86400
RDATA:
MNAME: ns1.example.com
RNAME: admin.example.com ([email protected])
SERIAL: 2024010101
REFRESH: 3600
RETRY: 600
EXPIRE: 604800
MINIMUM: 86400
用途:
- 标识区域权威信息
- 控制区域传输
- 设置缓存策略
MX记录 - 邮件交换
TYPE = 15
RDATA格式:
PREFERENCE: 优先级 (16位)
EXCHANGE: 邮件服务器域名
示例:
NAME: example.com
TYPE: MX (15)
TTL: 3600
RDATA:
PREFERENCE: 10
EXCHANGE: mail1.example.com
多个MX记录:
example.com MX 10 mail1.example.com
example.com MX 20 mail2.example.com
example.com MX 30 mail3.example.com
处理:
- 优先使用数值小的
- 同优先级随机选择
- 失败时尝试下一个
TXT记录 - 文本
TYPE = 16
RDATA = 任意文本字符串
示例:
NAME: example.com
TYPE: TXT (16)
TTL: 3600
RDATA: "v=spf1 include:_spf.google.com ~all"
用途:
- SPF (发件人策略框架)
- DKIM (域名密钥识别邮件)
- 域名验证
- 任意元数据
多个字符串:
RDATA可包含多个<length><string>对
AAAA记录 - IPv6地址
TYPE = 28
RDLENGTH = 16 (字节)
RDATA = 128位IPv6地址
示例:
NAME: example.com
TYPE: AAAA (28)
TTL: 3600
RDLENGTH: 16
RDATA: 2606:2800:220:1:248:1893:25c8:1946
编码:
IPv6地址按16字节网络序存储
PTR记录 - 反向解析
TYPE = 12
RDATA = 域名
用途: IP地址反向解析到域名
示例:
查询: 93.184.216.34的域名
NAME: 34.216.184.93.in-addr.arpa
TYPE: PTR (12)
RDATA: example.com
IPv6反向:
2606:2800:220:1::1
→ 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa
DNS消息压缩
为减小消息大小,DNS使用指针压缩重复的域名:
压缩格式:
域名标签长度:
- 00-3F: 普通标签长度 (0-63)
- C0-FF: 指针 (11xxxxxx xxxxxxxx)
指针格式:
11 <14位偏移量>
示例:
原始消息:
Offset 12: 3 "www" 7 "example" 3 "com" 0
Offset 30: 7 "example" 3 "com" 0
压缩后:
Offset 12: 3 "www" 7 "example" 3 "com" 0
Offset 30: C0 0x11 (指向偏移12+4="example")
节省:
30: "example.com" (12字节)
压缩为: C0 0x11 (2字节)
节省: 10字节
压缩示例:
查询: www.example.com, example.com的A记录
未压缩:
Question:
12: 3"www"7"example"3"com"0 (17字节)
Answer:
29: 3"www"7"example"3"com"0 (17字节)
46: 7"example"3"com"0 (13字节)
压缩后:
Question:
12: 3"www"7"example"3"com"0 (17字节)
Answer:
29: C0 0C (2字节,指向偏移12)
31: C0 10 (2字节,指向偏移16="example.com")
总节省: (17-2) + (13-2) = 26字节
DNS查询示例
完整的DNS查询/响应
# Python DNS查询示例
import socket
import struct
def build_dns_query(domain, qtype=1):
"""构造DNS查询消息"""
# Header
transaction_id = 0x1234
flags = 0x0100 # 标准查询,期望递归
qdcount = 1
ancount = 0
nscount = 0
arcount = 0
header = struct.pack('!HHHHHH',
transaction_id,
flags,
qdcount, ancount, nscount, arcount)
# Question
qname = b''
for part in domain.split('.'):
qname += struct.pack('B', len(part)) + part.encode()
qname += b'\x00' # 结束标记
question = qname + struct.pack('!HH', qtype, 1) # TYPE, CLASS
return header + question
def parse_dns_response(data):
"""解析DNS响应"""
# 解析Header
transaction_id, flags, qdcount, ancount, nscount, arcount = \
struct.unpack('!HHHHHH', data[:12])
print(f'Transaction ID: 0x{transaction_id:04x}')
print(f'Flags: 0x{flags:04x}')
print(f'Questions: {qdcount}')
print(f'Answers: {ancount}')
# 跳过Question部分
offset = 12
# (简化,实际需要解析QNAME)
while data[offset] != 0:
length = data[offset]
offset += length + 1
offset += 5 # 结束标记 + QTYPE + QCLASS
# 解析Answer
for _ in range(ancount):
# NAME (可能是指针)
if (data[offset] & 0xC0) == 0xC0:
# 指针
offset += 2
else:
# 完整域名
while data[offset] != 0:
length = data[offset]
offset += length + 1
offset += 1
# TYPE, CLASS, TTL, RDLENGTH
rtype, rclass, ttl, rdlength = struct.unpack('!HHIH',
data[offset:offset+10])
offset += 10
print(f'\nAnswer:')
print(f' Type: {rtype}')
print(f' TTL: {ttl}')
# RDATA
if rtype == 1: # A记录
ip = '.'.join(str(b) for b in data[offset:offset+4])
print(f' IP: {ip}')
offset += rdlength
def dns_query(domain, dns_server='8.8.8.8', port=53):
"""执行DNS查询"""
# 构造查询
query = build_dns_query(domain)
# 发送查询 (UDP)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5.0)
try:
sock.sendto(query, (dns_server, port))
response, _ = sock.recvfrom(512)
print(f'查询 {domain}:')
parse_dns_response(response)
finally:
sock.close()
# 使用
dns_query('example.com')
输出示例:
查询 example.com:
Transaction ID: 0x1234
Flags: 0x8180
Questions: 1
Answers: 1
Answer:
Type: 1
TTL: 3600
IP: 93.184.216.34
实用工具
dig命令详解
# 基本查询
dig example.com
# 指定记录类型
dig example.com A # IPv4
dig example.com AAAA # IPv6
dig example.com MX # 邮件服务器
dig example.com NS # 名称服务器
dig example.com TXT # 文本记录
# 指定DNS服务器
dig @8.8.8.8 example.com
# 追踪查询路径
dig +trace example.com
# 短格式输出
dig +short example.com
# 反向解析
dig -x 93.184.216.34
# TCP查询
dig +tcp example.com
# 查看完整响应
dig +noall +answer +additional example.com
nslookup使用
# 交互模式
nslookup
> example.com
> set type=MX
> example.com
> exit
# 命令行模式
nslookup example.com
nslookup -type=MX example.com
nslookup -type=NS example.com
host命令
# 简单查询
host example.com
# 详细输出
host -v example.com
# 指定记录类型
host -t MX example.com
host -t NS example.com
参考文献
核心RFC:
- [RFC 1034] Domain Names - Concepts and Facilities
- [RFC 1035] Domain Names - Implementation and Specification ← 本文档
扩展和更新:
- [RFC 2181] Clarifications to the DNS Specification
- [RFC 2308] Negative Caching of DNS Queries (DNS NCACHE)
- [RFC 4033] DNS Security Introduction and Requirements
- [RFC 4034] Resource Records for the DNS Security Extensions
- [RFC 4035] Protocol Modifications for the DNS Security Extensions
- [RFC 6891] Extension Mechanisms for DNS (EDNS(0))
相关协议:
- [RFC 8484] DNS Queries over HTTPS (DoH)
- [RFC 7858] Specification for DNS over Transport Layer Security (TLS)
总结: RFC 1035定义了DNS的实现细节,是理解DNS协议工作原理的关键文档。从消息格式到资源记录,从查询流程到压缩机制,本RFC为所有DNS实现提供了详细的规范。配合RFC 1034,您将全面掌握DNS系统!