从今天开始,我觉得自己已经开始在跟魔鬼打交道了,因为接触细节了嘛。如果说昨天那两个Encoding函数,只能算是赛前热身。那么今天应该算是开始进行比赛了,后面的这些问题全是细节问题。如果您只关注原理,大可不必为这章伤脑筋,跳过去就好。留下我一个人在这里,就当我在自虐好了。好吧,我们开始吧。
一,Name Service Query的Header
Name Service Query Header的话,是由下面的结构组成。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
NAME_TRN_ID | |||||||||||||||
R | OPCODE | NM_FLAGS | RCODE | ||||||||||||
QDCOUNT | |||||||||||||||
ANCOUNT | |||||||||||||||
NSCOUNT | |||||||||||||||
NAME_TRN_ID ARCOUNT |
NAME_TRN_ID:是事务编号,每次名字解析请求时,都会递增这个编号,以进行区别。我们为了简化,将这个值写死,写成1982好了。
R的定义是这样
R == 0 表示这是一个Request
R == 1 表示这是一个Response,,我们把它写死成0
OPCODE:定义 了六个操作码
0x0
== Query
0x5
== Name Registration
0x6
== Name Release
0x7
== WACK (Wait for Acknowledgement)
0x8
== Name Refresh
0x9
== Name Refresh (Alternate Opcode)
我们只是做名字查询,写死成0
NM_FLAGS:具体不解释拉,查书吧。写死成0x0010001
0 | 1 | 2 | 3 | 4 | 5 | 6 |
AA | TC | RD | RA | 0 | 0 |
B
|
RCODE: 返回码,每个请求会返回返回码中的一个,这里我们写死 0x00
最后,我们的名字查询格式如下。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
1982 | |||||||||||||||
0 | 0 0 0 0 | 0 0 1 0 0 0 1 | 0 0 0 0 | ||||||||||||
1 | |||||||||||||||
0 | |||||||||||||||
0 | |||||||||||||||
0 |
现在,我们按照这个格式将请求报文的头部编码成下面的数组。
unsigned char header[] =
{
0x07, 0xBE, /* 1982 == 0x07BE. */
0x01, 0x10, /* 0 0000 001
0001 0000
*/
0x00, 0x01, /* One name query. */
0x00, 0x00, /* Zero answers. */
0x00, 0x00, /* Zero authorities. */
0x00, 0x00 /* Zero additional. */
};
二,Query Entry
在头部后面,紧接着的就是Query Entry.
Query Entry = Level2Encoding(NBT) + QUESTION_TYPE + QUESTION_CLASS.
其中,QUESTION_TYPE则有下面两种可能的值。
NB == 0x0020
NBSTAT == 0x0021
我们这里则选择NB == 0x0020的情况。
对于QUESTION_CLASS 来说,只有唯一的一种类型,就是Internet Class: 0x0001 .
三,组成查询广播包
看起来,我们只要将上面的内容发往广播地址的UDP 137端口就可以了。