免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 961 | 回复: 0
打印 上一主题 下一主题

Sniffer分析文档 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-04-23 16:15 |只看该作者 |倒序浏览


Sniffer分析文档

1.1    DNS基础
DNS的名字空间和Unix的文件系统相似,也具有层次结构。图1 - 1 显示了这种层次的组织形式。
每个结点(图1-1中的圆圈)有一个至多6 3个字符长的标识。这颗树的树根是没有任何标识的特殊结点。命名标识中一律不区分大写和小写。命名树上任何一个结点的域名就是将从该结点到最高层的域名串连起来,中间使用一个点“.”分隔这些域名(注意这和U n i x文件系统路径的形成不同,文件路径是由树根依次向下的形成的)。域名树中的每个结点必须有一个唯一的域名,但域名树中的不同结点可使用相同的标识。
以点“ .”结尾的域名称为绝对域名或完全合格的域名FQDN(Full Qualified Domain
Name),例如sun.tuc.noao.edu .。如果一个域名不以点结尾,则认为该域名是不完全的。
如何使域名完整依赖于使用的DNS软件。如果不完整的域名由两个或两个以上的标号组成,

图1-1 DNS层次组织


1.1.1   DNS查询和响应报文格式
DNS定义了一个用于查询和响应的报文格式。图1 - 2显示这个报文的总体格式:




图1-2 DNS查询和响应的一般格式
    这个报文由1 2字节长的首部和4个长度可变的字段组成。标识字段由客户程序设置并由服务器返回结果。客户程序通过它来确定响应与查询是否匹配。
16 bit的标志字段被划分为若干子字段,如图1 - 3所示。

QR
opcode
AA
TC
RD
RA
(zero)
rcode
               1       4       1    1    1    1      3       4
图1-3  DNS报文首部中的标志字段
我们从最左位开始依次介绍各子字段:
ü         QR 是1 bit字段:0表示查询报文,1表示响应报文。
ü         opcode是一个4 bit字段:通常值为0(标准查询),其他值为1(反向查询)和2(服务器状态请求)。
ü         AA是1 bit标志,表示“授权回答(authoritative answer)”。该名字服务器是授权于该域的。
ü         TC是1 bit字段,表示“可截断的(truncated)”。使用U D P时,它表示当应答的总长度超过512字节时,只返回前512个字节。
ü         RD是1 bit字段表示“期望递归recursion desired)”。该比特能在一个查询中设置,并在响应中返回。这个标志告诉名字服务器必须处理这个查询,也称为一个递归查询。如果该位为0,且被请求的名字服务器没有一个授权回答,它就返回一个能解答该查询的
ü         其他名字服务器列表,这称为迭代查询。在后面的例子中,我们将看到这两种类型查询的例子。
ü         RA是1 bit字段,表示“可用递归”。如果名字服务器支持递归查询,则在响应中将该比特设置为1。在后面的例子中可看到大多数名字服务器都提供递归查询,除了某些根服务器。
ü         随后的3 bit字段必须为0。
ü         rcode是一个4 bit的返回码字段。通常的值为0(没有差错)和3(名字差错)。名字差错
ü         只有从一个授权名字服务器上返回,它表示在查询中制定的域名不存在。
ü         随后的4个16 bit 字段说明最后4个变长字段中包含的条目数。对于查询报文,问题(question)数通常是1,而其他3项则均为0。类似地,对于应答报文,回答数至少是1,剩下的两项可以是0或非0。
1.1.2  DNS查询报文中的问题部分
    问题部分中每个问题的格式如图1 4 - 5所示,通常只有一个问题。
图1-4 DNS查询报文中问题部分的格式
查询名是要查找的名字,它是一个或多个标识符的序列。每个标识符以首字节的计数值来说明随后标识符的字节长度,每个名字以最后字节为0结束,长度为0的标识符是根标识符。计数字节的值必须是0 ~ 6 3的数,因为标识符的最大长度仅为6 3(在本节的后面我们将看到计数字节的最高两比特为1,即值1 9 2 ~ 2 5 5,将用于压缩格式)。不像我们已经看到的许多其他报文格式,该字段无需以整32 bit边界结束,即无需填充字节。
图1 - 5显示了如何存储域名gemini.tuc.noao.edu。
图1-5域名gemini.tuc.noao.edu的表示

    每个问题有一个查询类型,而每个响应(也称一个资源记录,我们下面将谈到)也有一个类型。大约有2 0个不同的类型值,其中的一些目前已经过时。图1-6显示了其中的一些值。查询类型是类型的一个超集(superset):图中显示的类型值中只有两个能用于查询类型。
图1-6 DNS问题和响应的类型值和查询类型值
    最常用的查询类型是A类型,表示期望获得查询名的I P地址。一个P T R查询则请求获得一个I P地址对应的域名。这是一个指针查询,我们将在1 4 . 5节介绍。其他的查询类型将在1 4 . 6节介绍。
查询类通常是1,指互联网地址(某些站点也支持其他非I P地址)。
1.1.2 DNS响应报文中的资源记录部分
DNS报文中最后的三个字段,回答字段、授权字段和附加信息字段,均采用一种称为资源记录RR(Resource Record)的相同格式。图1-7显示了资源记录的格式。
图1-7 DNS资源记录格式
域名是记录中资源数据对应的名字。它的格式和前面介绍的查询名字段格式(图1 - 2)相同。类型说明R R的类型码。它的值和前面介绍的查询类型值是一样的。类通常为1,指Internet数据。生存时间字段是客户程序保留该资源记录的秒数。资源记录通常的生存时间值为2天。资源数据长度说明资源数据的数量。该数据的格式依赖于类型字段的值。对于类型1(A记录)资源数据是4字节的IP地址。
现在已经介绍了DNS查询和响应的基本格式,我们将通过分析sniffer程序的DNS报文解码过程来观察具体的程序实现。
1.2            DNS解码过程
DNS解码的过程实际是对DNS数据报处理的过程,解码程序处理的DNS数据由监听程序通过Plugin_data数据结构提供。下面我们就以sniffer程序中的解码程序dns_plugin.plug为例详细说明DNS的解码过程。
1.2.1  数据定义
10 struct PL_DNS_header
11 {
12     unsigned short id, flags;
13     unsigned short nr_quest, nr_answ_RR, nr_auth_RR, nr_add_RR;
14 };
15 int PL_pos_max;
16
17 #define PL_DNS_QR   0x8000
18 #define PL_DNS_OPCODE   0x7800
19 #define PL_DNS_AA   0x0400
20 #define PL_DNS_TC   0x0200
21 #define PL_DNS_RD   0x0100
22 #define PL_DNS_RA   0x0080
23 #define PL_DNS_RCODE    0x000F
图1.2.1.1
       10-14行定义DNS数据报的报头,DNS数据报报头由12字节组成(详见1.1中的DNS基础),17-23行定义了报头中16位的标志字段的值。
1.2.2  PL_DNS_plugin函数
71 void PL_DNS_plugin (struct Plugin_data *PLD)
72 {
73 struct IP_header *dns_iphead;
74 struct UDP_header *dns_udphead;
75 struct PL_DNS_header *dns_dnshead;
76 int i, j, dec_pos, answers, count, udp_start, len;
77 long pos;
78 unsigned char *so,*dest, *dns_p, *dns_buffer;
79 unsigned short fl, *r_dlen;
80 unsigned short *type, *class;
81
82 dns_buffer=PLD->PL_packet;
83 udp_start = PLD->PL_info.IP_len;
84 len=PLD->PL_info.IP_len + PLD->PL_info.UDP_len + PLD->PL_info.DATA_len;
85 dns_iphead= (struct IP_header *) dns_buffer;
86 dns_udphead= (struct UDP_header *) (dns_buffer+udp_start);
87 dns_dnshead= (struct DNS_header *) (dns_buffer+udp_start+sizeof(struct U
DP_header));
88
89 PL_pos_max = PLD->PL_info.DATA_len - 12;
90
91 so=(unsigned char *)&(dns_iphead->source);
92 dest=(unsigned char *)&(dns_iphead->destination);
93 if((ntohs(dns_udphead->source)!=53)&&(ntohs(dns_udphead->destination)!=5
3))
94                  return;

       73-80行定义变量,82-87行处理PLD数据结构,dns_buffer指针变量指向数据报的起始位置(包括IP头、UDP头、DNS头信息和数据),udp_start整型变量记录udp数据头在IP数据报中的偏移量(等于IP数据头的程度),len记录dns_buffer缓存的长度,dns_iphead结构指针指向dns_buffer的起始位置,dns­udphead结构指针指向dns_buffer中udp数据报的起始位置,dns_dnshead结构指针指向dns_buffer中DNS数据报的起始位置。
       89行的Pl_pos_max变量记录DNS数据报中的实际的数据长度(除了头部信息的其他数据)。
       91-94行获取IP数据报的源地址和目的地址并存入变量so和dest,然后判断udp数据报的源端口和目的端口是否为通用端口53,不是则返回。

95 printf("DNS Sniffit Plugin Report:\n");
96 printf("Packet: %u.%u.%u.%u %u -> %u.%u.%u.%u %u\n",
97         so[0],so[1],so[2],so[3],ntohs(dns_udphead->source),
98                 dest[0],dest[1],dest[2],dest[3],ntohs(dns_udphead->desti
nation));
99
100 printf("ID: %d \n",ntohs(dns_dnshead->id));
101 fl=ntohs(dns_dnshead->flags);
102
103 printf("  STATUS: %s ",(fl & PL_DNS_QR)? "Answer": "Query");
104 printf("(opcode: %X) , ",(fl & PL_DNS_OPCODE)>>11);
105 printf("%s , ",(fl & PL_DNS_AA)? "Auth. A.": "");
106 printf("%s , ",(fl & PL_DNS_TC)? "TRUNC": "");
107 printf("%s , ",(fl & PL_DNS_RD)? "Rec. Desired": "");
108 printf("%s , ",(fl & PL_DNS_RA)? "rec. Avail.": "rec. NOT Av.");
109 printf("ret: %d\n",(fl & PL_DNS_RCODE));
110
111 printf("  Q: %d  Answ: %d  Auth: %d  Add: %d",
112             ntohs(dns_dnshead->nr_quest),
113             ntohs(dns_dnshead->nr_answ_RR),
114             ntohs(dns_dnshead->nr_auth_RR),
115                 ntohs(dns_dnshead->nr_add_RR));
116
       10-115向终端输出DNS数据报的头部信息。

117 dns_p=(dns_buffer+udp_start+sizeof(struct UDP_header)+12);
118 dec_pos=0;
119 for(i=0;inr_quest);i++)
120   {
121   printf("\n  Query: ");
122   dec_pos=PL_DNS_decode(dns_p,dec_pos,NULL,0);
123   if(dec_pos
124   type=(unsigned short *) &(dns_p[dec_pos]);
125   class=(unsigned short *) &(dns_p[dec_pos+2]);
126   printf("\n    Type: %d   Class: %s",ntohs(*type),(ntohs(*class))?"IP":
    "Unknown");
127   dec_pos+=4;
128  }
129
       117-128行对DNS数据报中的数据解码,dns_p指向DNS数据报紧接头部信息的实际数据的起始位置,dec_pos记录被解码数据的当前位置。接下来的for循环调用解码函数PL_DNS_decode对dns_p指向的数据解码(dns_p指向的是查询响应报文段)。

130 if(fl & PL_DNS_TC)
131   {
132   printf("Truncated packet, not displayed...\n");
133         return;
134   }
135
136 /* dec_pos at beginning first answer field */
137 answers=ntohs(dns_dnshead->nr_answ_RR)+ntohs(dns_dnshead->nr_auth_RR)+
138         ntohs(dns_dnshead->nr_add_RR);
139 for(i=0;i
140   {
141   printf("\n  Answer %d/%d: ",i+1,answers);
142   dec_pos=PL_DNS_decode(dns_p,dec_pos,NULL,0);
143   if(dec_pos
144   type=(unsigned short *) &(dns_p[dec_pos]);
145   class=(unsigned short *) &(dns_p[dec_pos+2]);
146   printf("\n    Type: %d   Class: %s",ntohs(*type),(ntohs(*class))?"IP":
    "Unknown");
147   dec_pos+=8;
148   r_dlen=(unsigned short *)&(dns_p[dec_pos]);
149   dec_pos+=2;
150   if(ntohs(*type)==1)
151     {printf("\n    Data: ");
152     for(j=0;j
153         printf("%u.",(unsigned char)dns_p[dec_pos+j]);
154     }
155         dec_pos+=ntohs(*r_dlen);
156   }
157 printf("\n\n");
158 }


附录A:全局数据结构

                Plugin_data{}
PL_info
PL_iphead
PL_tcphead
PL_udphead
PL_data[MTU]
PL_packet[MTU]
图A.1
    图A.1的数据结构主要将DNS解码时所需的数据报信息传给解码程序,其中PL_info成员是由unwrap结构定义的结构变量,用来记录TCP、UDP、ICMP、IP等数据报的头部长度。接下来的三个数据成员PL_iphead、PL_tcphead、PL_udphead分别用来记录IP数据头、TCP数据头和UDP数据头。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/26031/showart_574104.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP