最近学习了下DNS的格式,发现很多内容都是转载自同一个而且说的不是很清楚,特再整理下
具体可以查看RFC1035 http://www.ietf.org/rfc/rfc1035.txt有详细的解释
对于英语理解不是很好和懒得看这么长的可以看下本文

首先是DNS数据帧的格式

+---------------------+
|        Header       | 报文头
+---------------------+
|       Question      | 查询的问题
+---------------------+
|        Answer       | 应答
+---------------------+
|      Authority      | 授权应答
+---------------------+
|      Additional     | 附加信息
+---------------------+

其中header报文头是必须有的,其他的有没有在报文头里有定义,报文头格式:

  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     请求客户端设置的16位标示,服务器给出应答的时候会带相同的标示字段回来,这样请求客户端就可以区分不同的请求应答了。

QR     1个比特位用来区分是请求(0)还是应答(1)。

OPCODE 4个比特位用来设置查询的种类,应答的时候会带相同值,可用的值如下:

0    标准查询 (QUERY)

1    反向查询 (IQUERY)

2    服务器状态查询 (STATUS)

3-15 保留值,暂时未使用

AA     授权应答(Authoritative Answer) - 这个比特位在应答的时候才有意义,指出给出应答的服务器是查询域名的授权解析服务器。

注意因为别名的存在,应答可能存在多个主域名,这个AA位对应请求名,或者应答中的第一个主域名。

TC     截断(TrunCation) - 用来指出报文比允许的长度还要长,导致被截断。

RD     期望递归(Recursion Desired) - 这个比特位被请求设置,应答的时候使用的相同的值返回。如果设置了RD,就建议域名服务器进行递归解析,递归查询的支持是可选的。

RA     支持递归(Recursion Available) - 这个比特位在应答中设置或取消,用来代表服务器是否支持递归查询。

Z      保留值,暂时未使用。在所有的请求和应答报文中必须置为0。

RCODE  应答码(Response code) - 这4个比特位在应答报文中设置,代表的含义如下:

0    没有错误。

   报文格式错误(Format error) - 服务器不能理解请求的报文。

2    服务器失败(Server failure) - 因为服务器的原因导致没办法处理这个请求。

3    名字错误(Name Error) - 只有对授权域名解析服务器有意义,指出解析的域名不存在。

   没有实现(Not Implemented) - 域名服务器不支持查询类型。

5    拒绝(Refused) - 服务器由于设置的策略拒绝给出应答。比如,服务器不希望对某些请求者给出应答,或者服务器不希望进行某些操作(比如区域传送zone transfer)。

6-15 保留值,暂时未使用。

QDCOUNT 无符号16位整数表示报文请求段中的问题记录数。

ANCOUNT 无符号16位整数表示报文回答段中的回答记录数。

NSCOUNT 无符号16位整数表示报文授权段中的授权记录数。

ARCOUNT 无符号16位整数表示报文附加段中的附加记录数。

然后是question的格式:

  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                                               |
|                     QNAME                     |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     QTYPE                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     QCLASS                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

QNAME   域名被编码为一些labels序列,每个labels包含一个字节表示后续字符串长度,以及这个字符串,以0长度和空字符串来表示域名结束。注意这个字段 可能为奇数字节,不需要进行边界填充对齐。比如www.isnowfy.com表示为03www07isnowfy03com00

QTYPE   2个字节表示查询类型,取值可以为任何可用的类型值,以及通配码来表示所有的资源记录。

QCLASS  2个字节表示查询的协议类。

 

其中QTYPE类型有

A               1 a host address

NS              2 an authoritative name server

MD              3 a mail destination (Obsolete - use MX)

MF              4 a mail forwarder (Obsolete - use MX)

CNAME           5 the canonical name for an alias

SOA             6 marks the start of a zone of authority

MB              7 a mailbox domain name (EXPERIMENTAL)

MG              8 a mail group member (EXPERIMENTAL)

MR              9 a mail rename domain name (EXPERIMENTAL)

NULL            10 a null RR (EXPERIMENTAL)

WKS             11 a well known service description

PTR             12 a domain name pointer

HINFO           13 host information

MINFO           14 mailbox or mail list information

MX              15 mail exchange

TXT             16 text strings

查询类型出现在问题字段中,查询类型是类型的一个超集,所有的类型都是可用的查询类型,其他查询类型如下:

AXFR            252 A request for a transfer of an entire zone

MAILB           253 A request for mailbox-related records (MB, MG or MR)

MAILA           254 A request for mail agent RRs (Obsolete - see MX)

              255 A request for all records

 

其中QCLASS类型有

IN              1 the Internet

CS              2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs)

CH              3 the CHAOS class

HS              4 Hesiod [Dyer 87]

查询类是类的一个超集

*               255 any class

 

应答格式:

  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                                               |
|                                               |
|                      NAME                     |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TYPE                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     CLASS                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TTL                      |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                   RDLENGTH                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|                     RDATA                     |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

NAME    资源记录包含的域名

TYPE    2个字节表示资源记录的类型,指出RDATA数据的含义

CLASS   2个字节表示RDATA的类

TTL     4字节无符号整数表示资源记录可以缓存的时间。0代表只能被传输,但是不能被缓存。

RDLENGTH        2个字节无符号整数表示RDATA的长度

RDATA   不定长字符串来表示记录,格式根TYPE和CLASS有关。比如,TYPE是A,CLASS 是 IN,那么RDATA就是一个4个字节的ARPA网络地址。

 

报文压缩:

为了减小报文,域名系统使用一种压缩方法来消除报文中域名的重复。使用这种方法,后面重复出现的域名或者labels被替换为指向之前出现位置的指针。

  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 1 1 |                OFFSET                   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

前两个比特位都为1。因为lablels限制为不多于63个字节,所以label的前两位一定为0,这样就可以让指针与label进行区分。(10 和 01 组合保留,以便日后使用) 。偏移值(OFFSET)表示从报文开始的字节指针。偏移量为0表示ID字段的第一个字节。

压缩方法让报文中的域名成为:

- 以0结尾的labels序列

- 一个指针

- 指针结尾的labels序列

指针只能在域名不是特殊格式的时候使用,否则域名服务器或解析器需要知道资源记录的格式。目前还没有这种情况,但是以后可能会出现。

如果报文中的域名需要计算长度,并且使用了压缩算法,那么应该使用压缩后的长度,而不是压缩前的长度。

程序可以自由选择是否使用指针,虽然这回降低报文的容量,而且很容易产生截断。不过所有的程序都应该能够理解收到的报文中包含的指针。

比如,一个报文需要使用域名F.ISI.ARPA,FOO.F.ISI.ARPA,ARPA,以及根。忽略报文中的其他字段,应该编码为:

  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
20|           1           |           F           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
22|           3           |           I           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
24|           S           |           I           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
26|           4           |           A           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
28|           R           |           P           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
30|           A           |           0           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40|           3           |           F           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42|           O           |           O           |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44| 1 1 |                20                       |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
64| 1 1 |                26                       |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
92|           0           |                       |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

偏移20的是域名F.ISI.ARPA。域名FOO.F.ISI.ARPA偏移40; 这样表示FOO的label后面跟着一个指向之前F.ISI.ARPA的指针。域名ARPA偏移64,使用一个指针指向F.ISI.ARPA的ARPA。 注意可以用这个指针是因为ARPA是从偏移位置20开始的labels序列中的最后一个label。 根域名在位置92定义为一个0,没有labels。

一个应答帧的例子:
0000  00 24 8c 87 39 7e 74 ea  3a 5b fe a4 08 00 45 00   .$..9~t. :[....E.
0010  00 91 55 bd 00 00 30 11  62 82 08 08 08 08 c0 a8   ..U...0. b.......
0020  01 65 00 35 ee c4 00 7d  78 64 3a 8b 81 80 00 01   .e.5...} xd:.....
0030  00 01 00 00 00 00 03 77 77 77 07 69 73 6e 6f 77   .......w ww.isnow
0040  66 79 03 63 6f 6d 00 00  1c 00 01 c0 0c 00 05 00   fy.com.. ........
0050  01 00 00 12 ab 00 02 c0 10                        ........ .
其中DNS帧从3a8b开始,3a8b是ID,flag8180,问题数1,回答数1,然后绿色部分是域名,回答是棕色部分,域名是c00c用的前面说的压缩方式