一、DNS协议
DNS协议是实现域名解析的核心协议,作为应用层协议其使用的传输层协议——主要场景用UDP协议,部分场景用TCP协议。
当前有DoH、DoT和DoQ等扩展协议,以解决明文泄露与劫持等问题:
- DoH:DNS over HTTPS,DNS报文封装在HTTPS(HTTP/2/3),RFC 8484
- DoT:DNS over TLS,在TCP之上直接加TLS加密,RFC 7858/8310
- DoQ:DNS over QUIC,基于QUIC协议,RFC 9250
二、DNS协议报文
理解DNS协议报文格式是掌握域名解析原理的关键,分为查询报文和响应报文两种类型,二者格式基本一致,仅部分字段功能存在差异。
下面简称DNS协议报文为DNS报文。
DNS报文采用固定格式的二进制结构,整体分为5个区域,按顺序排列如下:
| 区域 | 长度(字节) | 核心作用 |
|---|---|---|
| Header(首部) | 12 | - 包含:DNS报文的基础控制信息(比如“查询/响应标识”、“操作码”、“返回码”等) - 查询报文和响应报文都必有 |
| Question(问题区) | 可变 | 由条目构成。 - 条目包含:待解析的域名、解析类型 - 条目数量:查询报文=1,响应报文=0或者1 |
| Answer(回答区) | 可变 | 由条目构成。 - 条目包含:解析结果 - 条目数量:查询报文=0,响应报文>=0 |
| Authority(授权区) | 可变 | 由条目构成。 - 条目包含:1)传统条目,权威DNS服务器的域名;2)扩展条目,本文不深入 - 条目数量:查询报文=0,响应报文>=0 |
| Additional(附加区) | 可变 | 由条目构成。 - 条目包含:1)传统条目,授权区权威DNS服务器的IP地址;2)OPT扩展条目 - 条目数量:查询报文=0或者1,响应报文>=0 |
须知:本文实验过程中DNS报文由Wireshark捕获,其展示字段跟RFC不尽相同。
2.1、首部(Header)
2.1.1、含义
- 固定长度12字节
- 包含:DNS报文的基础控制信息,比如“查询/响应标识”、“操作码”、“返回码”等
- 查询报文和响应报文都必有
2.1.2、详细
首部是DNS报文的“控制中枢”,12字节被划分为6个2字节字段——ID,Flags,QDCOUNT,ANCOUNT,NSCOUNT和ARCOUNT,其中Flags字段又被细分为10个子字段,划分示意见表1,各个字段和子字段详细介绍见表2。
表1
| Offsets | Octet | 0 | 1 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Octet | Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 0 | 0 | ID (16 bits) | |||||||||||||||
| 2 | 16 | QR (1 bit) | Qpcode (4 bits) | AA (1 bit) | TC (1 bit) | RD (1 bit) | RA (1 bit) | Z (1 bit) | AD (1 bit) | CD (1 bit) | RCODE (4 bits) | ||||||
| 4 | 32 | QDCOUNT (16 bits) | |||||||||||||||
| 6 | 48 | ANCOUNT (16 bits) | |||||||||||||||
| 8 | 64 | NSCOUNT (16 bits) | |||||||||||||||
| 10 | 80 | ARCOUNT (16 bits) | |||||||||||||||
表2
| 字段(2字节) | 字段与子字段含义 |
|---|---|
| ID(标识) | 唯一标识一次DNS查询/响应会话:查询报文的ID为0x1234,针对该次查询的响应报文的ID也为0x1234 |
| Flags(标志位) | 2字节(16位)被细分为多个子字段,是首部的核心: 1、QR(1 bit):查询/响应报文标识 - 0 = 查询报文 - 1 = 响应报文 2、Opcode(4 bits):操作类型。查询报文设置,响应报文回显 - 0 = 标准查询,最常用,比如A记录解析 - 1 = 反向查询,事实废弃 - 2 = 状态查询,查询DNS服务器状态 - 3-15 = 保留,未公开使用 3、AA(Authoritative,1 bit):权威响应标识。查询报文无效,响应报文有效 - 1 = Answer(回答区)有响应结果,且该响应结果由该域名的权威DNS服务器给出 - 0 = 分为两种情形:1)Answer(回答区)有响应结果,但该响应结果不由该域名的权威DNS服务器给出,可能由转发DNS服务器或者递归DNS服务器给出;2)Answer(回答区)未有响应结果 4、TC(Truncated,1 bit):截断标识。查询报文和响应报文各自独立有效 - 1 = 报文长度超过UDP默认512字节,已被截断(需用TCP重传) - 0 = 未截断 5、RD(Recursion Desired,1 bit):递归查询标识。查询报文设置,响应报文回显 - 1 = 请求递归查询(服务器需直接返回最终结果) - 0 = 非递归查询(服务器仅返回已知信息,可能需要客户端进一步查询) 6、RA(Recursion Available,1 bit):递归可用标识。查询报文无效,响应报文有效 - 1 = 服务器支持递归查询 - 0 = 服务器不支持递归(若客户端请求了递归,会返回错误) 7、Z(1 bit):保留位,必须为0(未来扩展预留) 8、AD(Authentic Data,1 bit):标记响应数据是否经过DNSSEC验证。查询报文无效,响应报文有效 - 0 = 未验证 - 1 = 已验证 9、CD(Checking Disabled,1 bit):客户端控制是否执行DNSSEC签名验证。查询报文设置,响应报文回显 - 0 = 不禁用,由DNS服务器按照自身安全策略决定是否进行DNSSEC签名验证 - 1 = 禁用,禁止DNS服务器进行DNSSEC签名验证,即使DNS服务器本身安全策略要求进行DNSSEC签名验证 10、RCODE(4 bits):返回码,标识解析结果状态。查询报文无效,响应报文有效 - 0 = 成功 - 1 = 格式错误 - 2 = 服务器故障 - 3 = 域名不存在 - 4 = 不支持的操作 - 5 = 拒绝 - 6-15 = 保留 |
| QDCOUNT(问题区条目数量) | 16位无符号整型,条目数量:查询报文=1,响应报文=0或者1 |
| ANCOUNT(回答区条目数量) | 16位无符号整型,条目数量:查询报文=0,响应报文>=0 |
| NSCOUNT(授权区条目数量) | 16位无符号整型,条目数量:查询报文=0,响应报文>=0 |
| ARCOUNT(附加区条目数量) | 16位无符号整型,条目数量:查询报文=0或者1,响应报文>=0 |
2.1.3、实验
查询CNAME记录:dig baidu.com CNAME +short。
查询报文:
1 | Domain Name System (query) |
响应报文:
1 | Domain Name System (response) |
2.2、问题区(Question)
2.2.1、含义
- 可变字节
- 问题区由条目构成:
- 条目用于携带查询的具体信息,比如“要查询的域名”,“查询的资源记录类型”,“查询类”
- 条目数量(查询报文=1,响应报文=0或者1,由首部
QDCOUNT指定):响应报文通过包含问题区,能够明确地对应之前的查询请求,让接收方清楚地知道这次响应是针对哪个具体的查询做出的
2.2.2、条目格式
| 字段 | 长度(字节) | 含义与示例 |
|---|---|---|
| QNAME(域名) | 可变 | 域名有“常规格式”和“压缩格式”两种表示方式 常规格式:将域名按“.”分割为多个部分,每个部分前加1字节标识“部分长度”,最后用1字节 0x00标识域名结束,比如:域名 www.baidu.com按“.”分割为“www”,“baidu”和“com”3个部分,最后编码为0x03(部分长度) 0x77 0x77 0x77 0x05(部分长度) 0x62 0x61 0x69 0x64 0x75 0x03(部分长度) 0x63 0x6F 0x6D 0x00(标识域名结束)压缩格式:前2位为 11,用于标识压缩格式,后14位为“域名在报文中的偏移地址”,比如:若在报文偏移0x0C处存在相同域名,可编码为0xC00C(11000000,00001100)由于问题区在报文的位置,问题区条目域名一般只能使用常规格式 |
| QTYPE(类型) | 2 | 需要解析的记录类型,常见类型: - 0x0006 = SOA记录 - 0x0002 = NS记录 - 0x0001 = A记录 - 0x0005 = CNAME记录 - 0x000c = PTR记录 - 0x000f = MX记录 - 0x0010 = TXT记录 - 0x001c = AAAA记录 |
| QCLASS(类别) | 2 | 解析的网络类别,一般就为0x0001 = IN类(代表Internet) |
2.2.3、实验
查询TXT记录:dig 163.com txt +short。
响应报文:
1 | Domain Name System (response) |
2.3、回答区(Answer)
2.3.1、含义
- 可变字节
- 回答区由条目构成:
- 条目用于携带回答信息
- 条目数量(查询报文=0,响应报文>=0,由首部
ANCOUNT指定):不是必有,是可能“没配置相应DNS资源”、“不是直接结果,而是‘权威域名服务器’中间结果”、“查询失败”、“查询被拒绝”等情形
2.3.2、条目格式
| 字段 | 长度(字节) | 含义与示例 |
|---|---|---|
| NAME(域名) | 可变 | 含义和格式与问题区QNAME一致 |
| TYPE(类型) | 2 | 含义和格式与问题区QTYPE一致 |
| CLASS(类别) | 2 | 含义和格式与问题区QCLASS一致 |
| TTL(生存时间) | 4 | 32位有符号整型值,单位“秒”,表示该解析结果在DNS客户端所能缓存的有效时间,在“递归DNS服务器和转发DNS服务器查询相应DNS资源记录”场景,其作为DNS客户端,缓存时间也为该值 |
| RDLENGTH(数据长度) | 2 | 表示后续RDATA字段的字节数 |
| RDATA(记录数据) | 可变(跟RDLENGTH字段表征值一致) |
具体解析结果数据,格式由TYPE字段决定:- 若 0x0001 = A记录:RDATA为4字节IPv4地址- 若 0x001c = AAAA记录:RDATA为16字节IPv6地址- 若 0x0005 = CNAME记录:RDATA为目标域名,域名的表示方式跟问题区QNAME一致- 若 0x000f = MX记录:RDATA前2字节为“优先级”,后续字节为邮件服务器域名,域名的表示方式跟问题区QNAME一致 |
2.3.3、实验
1、实验1
查询AAAA记录:dig google.com AAAA +short。
响应报文:
1 | Domain Name System (response) |
2、实验2
查询AAAA记录:dig tiktok.com AAAA +short。
响应报文(未配置tiktok.com的AAAA记录,回答区为空):
1 | Domain Name System (response) |
2.4、授权区(Authority)
2.4.1、含义
- 可变字节
- 授权区由两类条目构成,两类条目数量之和“查询报文=0,响应报文>=0,由首部
NSCOUNT指定”:- 传统条目:
- 条目用于携带权威DNS服务器的域名信息:1)在回答区(Answer)为空时,存在的授权区(Authority)记录NS,表明——当前处于DNS迭代查询过程,DNS客户端下一步迭代查询的权威DNS服务器为NS;2)在回答区(Answer)不为空时,存在的授权区(Authority)记录NS,只是用来冗余告知DNS客户端该域名的权威DNS服务器列表
- 条目数量(查询报文=0,响应报文>=0)
- 扩展条目:
- RRSIG、NSEC3等类型扩展条目,本文不作深入
- 条目数量(查询报文=0,响应报文>=0)
- 传统条目:
2.4.2、条目格式
1、传统条目
条目格式跟回答区条目格式一致,差异在TYPE = 0x0002(即NS记录)。
2、扩展条目
条目格式跟回答区条目格式一致,差异在TYPE = 0x002e(即RRSIG记录)| 0x0032(即NSEC3记录)|...,本文不作深入。
2.4.3、实验
查询A记录,trace参数是为了模拟完整的DNS域名解析迭代过程:dig 163.com A +short +trace。
响应报文:
1 | Domain Name System (response) |
2.5、附加区(Additional)
2.5.1、含义
- 可变字节
- 附加区由两类条目构成,两类条目数量之和“查询报文=0或者1,响应报文>=0,由首部
ARCOUNT指定”:- 传统条目:
- 表示授权区权威DNS服务器域名对应的IP地址,从而减少查询
- 条目数量(查询报文=0,响应报文>=0)
- OPT扩展条目:
- OPT扩展条目在
EDNS(Extension Mechanisms for DNS)中定义[3],用于在不破坏原有DNS报文结构的前提下,突破512字节限制、扩展标志位与RCODE、支持DNSSEC等新功能 - 条目数量(查询报文=0或者1,响应报文=0或者1):附加区中最多只能有一条OPT扩展条目
- OPT扩展条目在
- 传统条目:
2.5.2、条目格式
1、传统条目
条目格式跟回答区条目格式一致,差异在TYPE一般是两个取值:
TYPE = 0x0001:A记录,该条目表示权威DNS服务器的IPv4地址TYPE = 0x001c:AAAA记录,该条目表示权威DNS服务器的IPv6地址
2、OPT扩展条目
为兼容,OPT扩展条目基于传统条目进行扩展,其格式如下。
| 长度(字节) | 旧字段名 | 旧字段含义与示例 | 新字段名 | 新字段含义与示例 |
|---|---|---|---|---|
| 可变 | NAME | 域名 | NAME | 固定值0x00 |
| 2 | TYPE | 类型 | TYPE | 固定值0x0029 |
| 2 | CLASS | 类别 | UDP Payload Size | UDP最大载荷 |
| 4 | TTL | 生存时间 | ||
| EXT-RCODE(1字节) | 扩展响应码,与首部RCODE组合为12位完整RCODE | |||
| EDNS-Version(1字节) | 目前固定为0x00 |
|||
| Z(2字节) | 高第1位DO(DNSSEC OK,1 bit): - 1 = 客户端支持并接受DNSSEC安全记录(RRSIG、NSEC、NSEC3、DNSKEY),递归服务器必须返回完整DNSSEC签名链给客户端,开启DNSSEC校验、防域名劫持/伪造 - 0 = 客户端不支持DNSSEC,服务器不返回RRSIG/NSEC/NSEC3,只返回普通业务记录(A/AAAA/CNAME),不做签名校验,无DNSSEC安全防护 低15位,固定为0值,用于未来扩展 |
|||
| 2 | RDLENGTH | 数据长度 | RDLENGTH | OPT数据总长度 |
| 可变 | RDATA | 记录数据 | RDATA | EDNS选项列表 |
2.5.3、实验
查询A记录,trace参数是为了模拟完整的DNS域名解析迭代过程:dig baidu.com A +short +trace。
查询报文:
1 | Domain Name System (query) |
响应报文:
1 | Domain Name System (response) |
参考文献
[1]https://datatracker.ietf.org/doc/html/rfc1035
[2]https://datatracker.ietf.org/doc/html/rfc2535
[3]https://datatracker.ietf.org/doc/html/rfc6891