Skip to main content

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系统!