DNS 线格式

最后更新: 2025-05-29 15:04:54 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

DNS 查询和响应以 12 字节标头开头,后面依次是 Question、Answer、Authority 和 Additional 区段。所有多八位组整数域均使用网络字节序。RFC 1035 定义了 基本格式;EDNS、DNSSEC 以及后续扩展在不改变基本标头的情况下增加记录和标头 语义。

标头 #

字段位数用途
ID16由客户端选择并在响应中回显的标识符
QR1查询(0)或响应(1)
Opcode4操作;QUERY 为零
AA1响应中的权威回答指示
TC1消息已被截断
RD1客户端请求递归
RA1服务器提供递归
Z3保留的基本位;扩展使用 AD 和 CD
RCODE4基本响应代码
QDCOUNT16Question 数量
ANCOUNT16Answer 记录数量
NSCOUNT16Authority 记录数量
ARCOUNT16Additional 记录数量

RD 请求接收服务器执行递归;RA 声明服务器能够执行递归。AA 表示响应 服务器对该回答具有权威性,并不表示消息中的每条记录都具有权威性。TC 告知 客户端,当截断的响应不足以完成处理时,必须通过 TCP 或其他受支持的传输方式 重试。

名称和 Question #

域名由一系列标签组成。每个普通标签以一个长度八位组开头,长度范围为 0 到 63; 长度为零的根标签终止该名称:

text
03 www 07 example 03 com 00

完整的编码名称(包括长度八位组和根标签)限制为 255 个八位组。Question 包含 QNAME、16 位的 QTYPE 和 16 位的 QCLASS;Internet 类别(IN)的值为 1。

为避免重复的后缀,名称可以使用压缩指针。指针的前两位为 11,其余 14 位是 相对于消息起始位置的偏移量。指针只能指向更早的位置。由于 DNS 消息是不可信的 输入,解析器必须限制指针深度、验证偏移量并检测循环。

Resource Record #

Answer、Authority 和 Additional 区段承载 Resource Record:

text
NAME | TYPE | CLASS | TTL | RDLENGTH | RDATA

TTL 编码在 32 位字段中,并依据 RFC 2181 作为非负的缓存生存期处理,其有效 范围为 0 到 \(2^{31}-1\)。RDLENGTH 界定特定类型 RDATA 字节的范围。RRset 是具有相同 owner name、class 和 type 的记录集合;DNSSEC 为 RRset 签名,而不是 为单条记录签名。

常见的 RDATA 包括四字节 IPv4 地址(A)、16 字节 IPv6 地址(AAAA)、域名 (NS、CNAME、PTR),以及结构化值,例如 MX 的 preference 加 exchange name,或 SOA 的计时器。RDATA 中的名称也可以使用压缩,但前提是适用的 RFC 允许这样做。

EDNS 使用 Additional 区段中的 OPT pseudo-record 来通告 UDP 负载大小、扩展的 RCODE 位、标志和选项。协商 EDNS 后,服务器不得假设 UDP DNS 受限于 512 字节; 但客户端仍必须处理截断并重试。

安全解析 #

将接收到的数据报或流帧视为唯一有效的字节范围。在读取每个定长字段、标签、指针 或 RDATA 值之前,验证整个字段仍位于该范围内。区段计数是不可信的;如果声明的 记录数量无法容纳,则停止解析。

名称解压需要两个位置:调用方下一个尚未读取的偏移量,以及用于重建名称的指针 跟随偏移量。统计指针跳转次数或跟踪已访问的偏移量以拒绝循环,拒绝保留的标签 前缀,强制执行 63 个八位组的标签限制和 255 个八位组的展开名称限制,并且绝不 解析消息范围之外的指针目标。

对于 TCP 和 TLS 传输,两个八位组的长度前缀为每条 DNS 消息提供帧边界,但它不是 DNS 标头的一部分。解析前必须准确读取指定长度的字节。对于 OPT 记录,将其 TTL 字段中的扩展 RCODE 与基本标头 RCODE 合并,并确保每个选项同时位于 RDLENGTH 和消息范围之内。

参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)