2012-11-14 34 views
0

我正在写一个程序来接收DNS信息并回应一个合适的答案(一个简单的DNS服务器,只答复A记录)。
但是当我收到消息时,它不像1035 RFC中描述的格式。
例如,这是通过NSLOOKUP产生的DNS查询:
我如何解密DNS的消息?

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

我知道DNS头和位在1035 RFC定义,但为什么它应该是十六进制?
我应该认为它们是十六进制数还是它们的utf-8等价物?
我的回复也应该有这种格式吗?

+1

这是在十六进制中,因为您用来打印出的代码在十六进制中打印了不可打印的字符。你可以用任何你喜欢的格式打印出来。 –

+0

你打电话给nslookup?在脚本中? – xxpor

+1

字节,字符,二进制,十六进制,UTF等...这些是人类的事情。计算机只处理位数,通常按8的倍数分组。不管你希望如何编写一个程序来解释这些位。 –

回答

5

它以十六进制形式出现,因为它是一个原始的二进制请求,但您大概试图将其打印为字符串。这显然是不可打印的字符是如何显示的,无论你用什么打印出来;它将它们作为十六进制序列转义。

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

取消平铺那么,让我们来看看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地址。

+0

tnx,这是非常有用的。你也会说明一个回应吗? – sia