我该如何破译dns消息?

时间:2012-11-14 04:05:14

标签: sockets networking dns network-programming rfc1035

我正在编写一个程序来接收dns消息并回复一个合适的答案(一个只回复A记录的简单dns服务器)。
但是当我收到消息时,它与1035 RFC中描述的格式不同。
例如,这是nslookup生成的dns查询:

'\xe1\x0c\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x06google\x03com\x00\x00\x01\x00\x01'

我知道1035 RFC中定义的dns头和位,但为什么它应该是十六进制? 我应该将它们视为十六进制数或它们的utf-8当量吗? 我的回答是否也应该有这种格式?

1 个答案:

答案 0 :(得分:6)

它以十六进制形式出现,因为它是原始二进制请求,但您可能会尝试将其作为字符串打印出来。这显然是如何通过你用来打印出来的不可打印字符来显示的;它以十六进制序列的形式逃脱它们。

您根本不将其解释为“hex”或UTF-8;您需要解释RFC描述的二进制格式。如果您提到您正在使用的语言,我(或其他人)可能会向您描述如何以二进制格式处理数据。

Untile那么,让我们看一下RFC 1035,看看如何手动解释你的查询:

The header contains the following fields:

                                    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                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

每行有16位,所以这是12个字节。让我们把前12个字节填入那里:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   ID = e10c                   |  \xe1 \x0c
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    | 0|  Opcode=0 | 0| 0| 1| 0| Z=0    |  RCODE=0  |  \x01 \x00
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  QDCOUNT = 1                  |  \x00 \x01
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  ANCOUNT = 0                  |  \x00 \x00
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  NSCOUNT = 0                  |  \x00 \x00
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  ARCOUNT = 0                  |  \x00 \x00
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

因此。我们有一个ID = e10c的查询(只是一个任意数字,所以客户端可以将查询与响应匹配),QR = 0表示它是一个查询,opcode = 0表示它是一个标准查询,AA和TC对于响应,RD = 1表示需要递归(我们正在对我们的本地名称服务器进行递归查询)。 Z保留供将来使用,RCODE是响应的响应代码。 QDCOUNT = 1表示我们有1个问题,其余的都是响应中不同类型记录的数量。

现在我们来问问题。每种都有以下格式:

                                    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是查询的名称。格式为一个八位字节,表示标签的长度,后跟标签,以0长度的标​​签终止。

所以我们有:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |       LEN = 6         |           g           |  \x06 g
    |           o           |           o           |  o    o
    |           g           |           l           |  g    l
    |           e           |       LEN = 3         |  e    \x03
    |           c           |           o           |  c    o
    |           m           |       LEN = 0         |  m    \x00
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   QTYPE = 1                   |  \x00 \x01
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  QCLASS = 1                   |  \x00 \x01
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

这表明我们正在查找的名称是google.com(有时写为google.com.,最后的空标签是明确的)。 QTYPE = 1是A(IPv4地址)记录。 QCLASS = 1是IN(互联网)查询。所以这就是要求google.com的IPv4地址。