参考资料:
以客户端的角度,根据相关协议的 RFC 文档内容来计算 IPv4 网络中一次 DNS 查询会产生多少网络流量。
根据 RFC 1122 TCP/IP 模型可以知道,要计算一次 DNS 查询所产生的流量,首先需要知道 DNS 协议在应用层产生的数据大小,然后根据传输层 TCP 或 UDP 协议计算出数据封包后的大小,最后根据网络层 IP 协议计算出实际产生的流量。
应用层 – DNS
参考资料:
根据 RFC 1035 中的定义,域名以 Label 组成,以长度为零的 Label 结束,只能包含 ASCII 字符中的字母(A-Za-z)、数字(0-9)以及 -
(注1、注2)。每个 Label 的长度最大为 63 Byte,域名的总的最大长度为 253 Byte(注3)。所有的域名都有一个根域,完整的域名应该为 example.com.
,DNS 应用在查询时会自动补全最后的 .
。 RFC 中对域名定义为大小写不敏感,example.com
与 EXAMPLE.COM
会获得相同的查询记录,但浏览器 URL 中除了 scheme
与 host
,其他部分是大小写敏感的。如果后端没有进行处理, http://example.com/a
与 http://example.com/A
是指向不同的资源。
- 注1:RFC 1035 规定 Label 必须以字母开头,但是 RFC1123 – 6.1.3.5 中去掉了这个限制。
- 注2:在浏览器中可以输入非 ASCII 字符作为域名,实际是使用基于 Punycode 码的 IDNA 系统,将 Unicode 字符串映射为有效的 DNS 字符集。
- 注3:RFC 1035 规定域名最大长度为 255 Byte,但根据 RFC 中的编码规则,
.
并不会参与编码,除了 Label 字符串需要编码外还需要将 Label 的长度进行编码,加上最后的长度为 0 的 Label,因此实际可用长度为 253 Byte。
Message
DNS 协议通信的消息格式只有一种,分为 5 个部分,Header
是一定存在的,其他部分在一些情况下为空。
+---------------------+
| Header |
+---------------------+
| Question | the question for the name server
+---------------------+
| Answer | RRs answering the question
+---------------------+
| Authority | RRs pointing toward an authority
+---------------------+
| Additional | RRs holding additional information
+---------------------+
Header
Header
是必须存在的,大小固定为 12 Byte。
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 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
字段 | 长度 | 说明 |
---|---|---|
ID | 2 Byte | A 16 bit identifier assigned by the program that generates any kind of query. |
QR | 1 Bit | A one bit field that specifies whether this message is a query (0), or a response (1). |
OPCODE | 4 Bit | A four bit field that specifies kind of query in this message. |
AA | 1 Bit | Authoritative Answer – this bit is valid in responses, and specifies that the responding name server is an authority for the domain name in question section. |
TC | 1 Bit | TrunCation – specifies that this message was truncated due to length greater than that permitted on the transmission channel. |
RD | 1 Bit | Recursion Desired – this bit may be set in a query and is copied into the response. |
RA | 1 Bit | Recursion Available – this be is set or cleared in a response, and denotes whether recursive query support is available in the name server. |
Z | 3 Bit | Reserved for future use. |
RCODE | 4 Bit | Response code – this 4 bit field is set as part of responses. |
QDCOUNT | 2 Byte | an unsigned 16 bit integer specifying the number of entries in the question section. |
ANCOUNT | 2 Byte | an unsigned 16 bit integer specifying the number of resource records in the answer section. |
NSCOUNT | 2 Byte | an unsigned 16 bit integer specifying the number of name server resource records in the authority records section. |
ARCOUNT | 2 Byte | an unsigned 16 bit integer specifying the number of resource records in the additional records section. |
Question
查询时 Question
是必须存在的,其中 QTYPE
和 QCLASS
为固定长度,QNAME
是可变长度,由所查询的域名长度决定。
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 | variable | a domain name represented as a sequence of labels, where each label consists of a length octet followed by that number of octets. |
QTYPE | 2 Byte | a two octet code which specifies the type of the query. |
QCLASS | 2 Byte | a two octet code that specifies the class of the query. |
QNAME
为可变长度,域名会被编码为 {label-length}{label-string}...{label-length}{label-string}0
,所以实际占用的数据会多 2 Byte。
Resource Record
Answer
Authority
Additional
的结构是相同的,NAME
与 RDATA
是可变的。
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 | variable | a domain name to which this resource record pertains. |
TYPE | 2 Byte | two octets containing one of the RR TYPE codes. |
CLASS | 2 Byte | two octets containing one of the RR CLASS codes. |
TTL | 4 Byte | a 32 bit signed integer that specifies the time interval that the resource record may be cached before the source of the information should again be consulted. |
RDLENGTH | 2 Byte | an unsigned 16 bit integer that specifies the length in octets of the RDATA field. |
RDATA | variable | a variable length string of octets that describes the resource. |
NAME
的长度最少为 2 Byte,当 NAME
中的字节前两 Bit 都为 1 时,表示后面的 14 Bit 是一个偏移量,代表从 Message 开始部分偏移。Label 的长度编码前两 Bit 需要是 0(01 和 10 作为保留),也就是 Label 长度最大为 63 的原因。
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 1 1| OFFSET |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
RDATA
的大小根据不同类型的记录格式有所不同, A 记录以 32 Bit 来表示一个 IPV4 地址。
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ADDRESS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
传输层 – UDP
参考资料:
虽然 DNS 支持 UDP 和 TCP,不过最常用的是 UDP,根据 RFC 768 中 UDP 报文结构的定义可以得到 UDP 报文会为数据增加 8 Byte 的头部信息。
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source Port | Destination Port|
+--------+--------+--------+--------+
| Length | Checksum |
+--------+--------+--------+--------+
|
| data octets ...
+---------------- ...
字段 | 长度 | 说明 |
---|---|---|
Source Port | 2 Byte | Source Port is an optional field, when meaningful, it indicates the port of the sending process, and may be assumed to be the port to which a reply should be addressed in the absence of any other information. |
Destination Port | 2 Byte | Destination Port has a meaning within the context of a particular internet destination address. |
Length | 2 Byte | Length is the length in octets of this user datagram including this header and the data. |
Checksum | 2 Byte | Checksum is the 16-bit one’s complement of the one’s complement sum of a pseudo header of information from the IP header, the UDP header, and the data, padded with zero octets at the end (if necessary) to make a multiple of two octets. |
由于 Length
的大小是 2 Byte,因此 UDP 包理论最大为 2^16 Byte,减去 8 Byte 的首部,有效负载数据大小为 2^16 – 8 Byte。
网络层 – IP
参考资料:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IHL
大小为 4 Bit,使用十进制表示 IP 协议头部的长度为多少个 32 Bit,最小值为 5,最大值为 15,因此 IP 协议头部的最大长度为 60 Byte。当 IHL
大于 5 时,Options
才会有数据,并且需要 Padding
来保证 IP 协议头部大小一定是 32 Bit 的整数倍。通常情况下 IP 协议头部的大小为 20 Byte。
IPv4 中是在 IP 协议中根据 MTU 进行分片,虽然 UDP 包的理论大小限制远大于 MTU 的 1500 Byte(注1),但是分片会带来额外的消耗,使用 UDP 协议时需根据 MTU 设置包大小。
- 注1:1500 Byte 需要减去网络层 IP 协议使用的 20 Byte 与 UDP Header 使用的 8 Byte ,实际可负载的数据大小为 1472 Byte。
链路层
参考资料:
以太网的帧格式事实标准是 Ethernet II Type,在这个阶段会增加 14 Bytes 的 MAC Header 和 4 Byte 的 CRC Checksum。
计算
根据以上的所有信息计算请求流量和响应流量。
查询请求
以查询 example.com
的 A 记录为例进行计算。
- 应用层
查询的 Message
只有 Header
与 Question
两个部分,Header
长度固定为 12 Byte。Question
部分中 QNAME
因为 example.com
会被编码为 7example3com0
占用长度为 13 Byte,而 QTYPE
与 QCLASS
长度合计为 4 Byte,最终 DNS 应用层产生的数据大小为 27 Byte。
- 传输层
传输层使用 UDP 协议,因此需要增加 8 Byte UDP Header,这时的数据大小为 35 Byte。
- 网络层
网络层使用 IP 协议,增加 20 Byte IP Header,此时的数据大小为 55 Byte。
- 链路层
链路层使用 Ethernet II Type 帧格式封装,增加 14 Byte MAC Header 和 4 Byte 的 CRC Checksum,最终的数据为 73 Byte。
响应结果
为了方便计算,假设仅返回一条记录。
- 应用层
相对查询的 Message
增加了 Answer
部分,由 Header
、Question
、Answer
三个部分组成。因为 Header
与 Question
没有变化,因此只需要计算 Answer
的大小即可。
NAME
长度因为 example.com
已经在 Question
中出现过,因此为 2 Byte。TYPE
、CLASS
、TTL
与 RDLENGTH
为固定大小,合计为 10 Byte。A 记录的 RDATA
大小为 4 Byte,Answer
部分总大小为 16 Byte,DNS 应用层的数据大小为 43 Byte。
- 传输层
传输层使用 UDP 协议,因此需要增加 8 Byte UDP Header,这时的数据大小为 51 Byte。
- 网络层
网络层使用 IP 协议,增加 20 Byte IP Header,此时的数据大小为 71 Byte。
- 链路层
链路层使用 Ethernet II Type 帧格式封装,增加 14 Byte MAC Header 和 4 Byte 的 CRC Checksum,最终的数据为 89 Byte。
总结
对 example.com
的 A 记录进行一次查询,客户端会发出 73 Byte 的数据,接收 89 Byte 的数据,发出、接收各一个 UDP 包。
验证
可以使用抓包工具 Wireshark 来进行验证,安装好 Wireshark 之后,设置过滤器为 udp port 53
进行抓包,由于 DNS 有缓存机制,推荐使用命令行工具发起 DNS 查询请求。
另外需要注意,根据官方文档 [7.10.2. Checksum offloading][] 的说法,网卡驱动会将 CRC Checksum 的处理交给硬件完成,因此 Wireshark 无法获取到。