一步一步开发sniffer(Winpcap+MFC)(五)莫道无人能识君,其实我懂你的心——解析数据包(转)

前文已经讲过,解析数据包主要通过analyze_frame()这个函数实现的,实际上并非这个函数完成了所有的功能,其实从名字就可以看出,它只是完成了对“帧”的解析,也就是链路层数据的解析,还有analyze_arp()、analyze_ip()、analyze_ip6()、analyze_icmp()……等来完成其他协议层的解析工作。

为什么会这样定义?熟悉协议栈工作流程的都知道,数据是由应用层把数据加上应用层协议头后给传输层,传输层在最外面加上它的头部后给网络层,网络层在外面加上它的头部后再给链路层……所以当数据包被捕获到之后最外面的就是链路层的协议头,因此首先要解析的就是链路层协议,这也就是为什么首先要调用analyze_frame()这个函数了,然后再一层一层把它“剥开”,最终获得里面的数据。

每一层的上层可能有多种协议在工作,比如IP上层就有TCP和UDP等之分,所以在解析数据包的时候需要根据不同的特征来判断上层协议到底是什么,然后再来调用相关的函数对其进行解析,下面将列出一些主要的判断特征:

1、  链路层--网络层

网络层可能会有arp、ipv4、ipv6这三种不同的情况,在链路层定义了一个type字段,专门用于指示网络层数据包是什么类型。

type == 0x0806 表示这是一个arp包

type == 0x0800 表示这是一个ipv4包

type == 0x86dd 表示这是一个ipv6包

2、  网络层(IP层)--传输层

IP层之上可能会有tcp、udp、icmp等

IPv4协议定义了proto字段来指示传输层协议是什么。还记得上一章的Protocol.h文件中的这段定义不?proto什么值对应什么协议很明白了吧?

#definePROTO_ICMP 1

#define PROTO_TCP 6

#define PROTO_UDP 17

IPv6使用nh字段来标明传输层协议,如下:

nh== 0x3a 表示上层是icmpv6

nh== 0x06 表示上层是tcp

nh== 0x11 表示上层是udp

3、  传输层之上就是应用层了,这里我们的应用层只支持http协议,判断方法很简单,就是看目的或源端口是不是80。

余下的工作就是一个字段一个字段地获取数据包的值了。函数的整体调用关系如下图:

需要特别说明的一点是,网络中的字节顺序跟主机中的字节顺序是完全不一样的,所以特别是要获得数字的值的时候,一定要先调用ntohs()函数(network to host short)或ntohl()函数(network to host long)将数据包的网络字节顺转换为主机字节序,这样在做一些判断的时候才是准确的。

下一章:千呼万唤始出来,不抱琵琶也露面——将解析数据写到GUI上

解析函数的代码如下:

[cpp] view plaincopy

    1. /*pkt为网络中捕获的包,data为要存为本机上的数据*/
    2. /*分析链路层*/
    3. int analyze_frame(const u_char * pkt,struct datapkt * data,struct pktcount *npacket)
    4. {
    5. int i;
    6. struct ethhdr *ethh = (struct ethhdr*)pkt;
    7. data->ethh = (struct ethhdr*)malloc(sizeof(struct ethhdr));
    8. if(NULL == data->ethh)
    9. return -1;
    10. for(i=0;i<6;i++)
    11. {
    12. data->ethh->dest[i] = ethh->dest[i];
    13. data->ethh->src[i] = ethh->src[i];
    14. }
    15. npacket->n_sum++;
    16. /*由于网络字节顺序原因,需要对齐*/
    17. data->ethh->type = ntohs(ethh->type);
    18. //处理ARP还是IP包?
    19. switch(data->ethh->type)
    20. {
    21. case 0x0806:
    22. return analyze_arp((u_char*)pkt+14,data,npacket);      //mac 头大小为14
    23. break;
    24. case 0x0800:
    25. return analyze_ip((u_char*)pkt+14,data,npacket);
    26. break;
    27. case 0x86dd:
    28. return analyze_ip6((u_char*)pkt+14,data,npacket);
    29. return -1;
    30. break;
    31. default:
    32. npacket->n_other++;
    33. return -1;
    34. break;
    35. }
    36. return 1;
    37. }
    38. /*分析网络层:ARP*/
    39. int analyze_arp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    40. {
    41. int i;
    42. struct arphdr *arph = (struct arphdr*)pkt;
    43. data->arph = (struct arphdr*)malloc(sizeof(struct arphdr));
    44. if(NULL == data->arph )
    45. return -1;
    46. //复制IP及MAC
    47. for(i=0;i<6;i++)
    48. {
    49. if(i<4)
    50. {
    51. data->arph->ar_destip[i] = arph->ar_destip[i];
    52. data->arph->ar_srcip[i] = arph->ar_srcip[i];
    53. }
    54. data->arph->ar_destmac[i] = arph->ar_destmac[i];
    55. data->arph->ar_srcmac[i]= arph->ar_srcmac[i];
    56. }
    57. data->arph->ar_hln = arph->ar_hln;
    58. data->arph->ar_hrd = ntohs(arph->ar_hrd);
    59. data->arph->ar_op = ntohs(arph->ar_op);
    60. data->arph->ar_pln = arph->ar_pln;
    61. data->arph->ar_pro = ntohs(arph->ar_pro);
    62. strcpy(data->pktType,"ARP");
    63. npacket->n_arp++;
    64. return 1;
    65. }
    66. /*分析网络层:IP*/
    67. int analyze_ip(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    68. {
    69. int i;
    70. struct iphdr *iph = (struct iphdr*)pkt;
    71. data->iph = (struct iphdr*)malloc(sizeof(struct iphdr));
    72. if(NULL == data->iph)
    73. return -1;
    74. data->iph->check = iph->check;
    75. npacket->n_ip++;
    76. /*for(i = 0;i<4;i++)
    77. {
    78. data->iph->daddr[i] = iph->daddr[i];
    79. data->iph->saddr[i] = iph->saddr[i];
    80. }*/
    81. data->iph->saddr = iph->saddr;
    82. data->iph->daddr = iph->daddr;
    83. data->iph->frag_off = iph->frag_off;
    84. data->iph->id = iph->id;
    85. data->iph->proto = iph->proto;
    86. data->iph->tlen = ntohs(iph->tlen);
    87. data->iph->tos = iph->tos;
    88. data->iph->ttl = iph->ttl;
    89. data->iph->ihl = iph->ihl;
    90. data->iph->version = iph->version;
    91. //data->iph->ver_ihl= iph->ver_ihl;
    92. data->iph->op_pad = iph->op_pad;
    93. int iplen = iph->ihl*4;                          //ip头长度
    94. switch(iph->proto)
    95. {
    96. case PROTO_ICMP:
    97. return analyze_icmp((u_char*)iph+iplen,data,npacket);
    98. break;
    99. case PROTO_TCP:
    100. return analyze_tcp((u_char*)iph+iplen,data,npacket);
    101. break;
    102. case PROTO_UDP:
    103. return analyze_udp((u_char*)iph+iplen,data,npacket);
    104. break;
    105. default :
    106. return-1;
    107. break;
    108. }
    109. return 1;
    110. }
    111. /*分析网络层:IPV6*/
    112. int analyze_ip6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    113. {
    114. int i;
    115. struct iphdr6 *iph6 = (struct iphdr6*)pkt;
    116. data->iph6 = (struct iphdr6*)malloc(sizeof(struct iphdr6));
    117. if(NULL == data->iph6)
    118. return -1;
    119. npacket->n_ip6++;
    120. data->iph6->version = iph6->version;
    121. data->iph6->flowtype = iph6->flowtype;
    122. data->iph6->flowid = iph6->flowid;
    123. data->iph6->plen = ntohs(iph6->plen);
    124. data->iph6->nh = iph6->nh;
    125. data->iph6->hlim =iph6->hlim;
    126. for(i=0;i<16;i++)
    127. {
    128. data->iph6->saddr[i] = iph6->saddr[i];
    129. data->iph6->daddr[i] = iph6->daddr[i];
    130. }
    131. switch(iph6->nh)
    132. {
    133. case 0x3a:
    134. return analyze_icmp6((u_char*)iph6+40,data,npacket);
    135. break;
    136. case 0x06:
    137. return analyze_tcp((u_char*)iph6+40,data,npacket);
    138. break;
    139. case 0x11:
    140. return analyze_udp((u_char*)iph6+40,data,npacket);
    141. break;
    142. default :
    143. return-1;
    144. break;
    145. }
    146. //npacket->n_ip6++;
    147. //strcpy(data->pktType,"IPV6");
    148. return 1;
    149. }
    150. /*分析传输层:ICMP*/
    151. int analyze_icmp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    152. {
    153. struct icmphdr* icmph = (struct icmphdr*)pkt;
    154. data->icmph = (struct icmphdr*)malloc(sizeof(struct icmphdr));
    155. if(NULL == data->icmph)
    156. return -1;
    157. data->icmph->chksum = icmph->chksum;
    158. data->icmph->code = icmph->code;
    159. data->icmph->seq =icmph->seq;
    160. data->icmph->type = icmph->type;
    161. strcpy(data->pktType,"ICMP");
    162. npacket->n_icmp++;
    163. return 1;
    164. }
    165. /*分析传输层:ICMPv6*/
    166. int analyze_icmp6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    167. {
    168. int i;
    169. struct icmphdr6* icmph6 = (struct icmphdr6*)pkt;
    170. data->icmph6 = (struct icmphdr6*)malloc(sizeof(struct icmphdr6));
    171. if(NULL == data->icmph6)
    172. return -1;
    173. data->icmph6->chksum = icmph6->chksum;
    174. data->icmph6->code = icmph6->code;
    175. data->icmph6->seq =icmph6->seq;
    176. data->icmph6->type = icmph6->type;
    177. data->icmph6->op_len = icmph6->op_len;
    178. data->icmph6->op_type = icmph6->op_type;
    179. for(i=0;i<6;i++)
    180. {
    181. data->icmph6->op_ethaddr[i] = icmph6->op_ethaddr[i];
    182. }
    183. strcpy(data->pktType,"ICMPv6");
    184. npacket->n_icmp6++;
    185. return 1;
    186. }
    187. /*分析传输层:TCP*/
    188. int analyze_tcp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    189. {
    190. struct tcphdr *tcph = (struct tcphdr*)pkt;
    191. data->tcph = (struct tcphdr*)malloc(sizeof(struct tcphdr));
    192. if(NULL == data->tcph)
    193. return -1;
    194. data->tcph->ack_seq = tcph->ack_seq;
    195. data->tcph->check = tcph->check;
    196. data->tcph->doff = tcph->doff;
    197. data->tcph->res1 = tcph->res1;
    198. data->tcph->cwr = tcph->cwr;
    199. data->tcph->ece = tcph->ece;
    200. data->tcph->urg = tcph->urg;
    201. data->tcph->ack = tcph->ack;
    202. data->tcph->psh = tcph->psh;
    203. data->tcph->rst = tcph->rst;
    204. data->tcph->syn = tcph->syn;
    205. data->tcph->fin = tcph->fin;
    206. //data->tcph->doff_flag = tcph->doff_flag;
    207. data->tcph->dport = ntohs(tcph->dport);
    208. data->tcph->seq = tcph->seq;
    209. data->tcph->sport = ntohs(tcph->sport);
    210. data->tcph->urg_ptr = tcph->urg_ptr;
    211. data->tcph->window= tcph->window;
    212. data->tcph->opt = tcph->opt;
    213. /////////////////////*不要忘记http分支*/////////////////////////
    214. if(ntohs(tcph->dport) == 80 || ntohs(tcph->sport)==80)
    215. {
    216. npacket->n_http++;
    217. strcpy(data->pktType,"HTTP");
    218. }
    219. else{
    220. npacket->n_tcp++;
    221. strcpy(data->pktType,"TCP");
    222. }
    223. return 1;
    224. }
    225. /*分析传输层:UDP*/
    226. int analyze_udp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
    227. {
    228. struct udphdr* udph = (struct udphdr*)pkt;
    229. data->udph = (struct udphdr*)malloc(sizeof(struct udphdr));
    230. if(NULL == data->udph )
    231. return -1;
    232. data->udph->check = udph->check;
    233. data->udph->dport = ntohs(udph->dport);
    234. data->udph->len = ntohs(udph->len);
    235. data->udph->sport = ntohs(udph->sport);
    236. strcpy(data->pktType,"UDP");
    237. npacket->n_udp++;
    238. return 1;
    239. }
时间: 2024-10-15 08:52:06

一步一步开发sniffer(Winpcap+MFC)(五)莫道无人能识君,其实我懂你的心——解析数据包(转)的相关文章

c语言Winpcap编程构造并接收解析arp包

/* 程序功能: 1.构造arp包,并发送.程序参数顺序:源IP.目的IP.mac地址.flag 2.获取网络中的ARP数据包,解析数据包的内容.程序参数:日志文件名 winpacp中文技术文档(基本是英文的):http://www.ferrisxu.com/WinPcap/html/index.html */ 一.构造arp包 在构造之前先了解一下arp包的结构,先从网上找了张图 从图中可以看出以太网首部占14字节,以太网ARP字段占28字节.其中op字段为操作类型,1表示ARP请求.2表示A

一步一步学习Swift之(一):关于swift与开发环境配置

一.什么是Swift? 1.Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用. 2.Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制. 3.Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣. 4.Swift 是基于成熟而且倍受喜爱的 Cocoa 和 Cocoa Touch 框架,它的降临将重新定义软件开发. 5.Swift 是编写 iOS 和 OS X 应用的极佳手段,并将伴随着新的特性和功能持续演进.

windows phone开发第一步:搭建软件开发环境

windows phone开发第一步:搭建软件开发环境:http://www.cnblogs.com/hanjun/archive/2012/10/09/2716669.html

一步一步开发属于自己的SharePoint 2010工作流

一步一步开发属于自己的SharePoint 2010工作流 分类: sharepoint MOSS2013-03-17 08:26 376人阅读 评论(0) 收藏 举报 目录(?)[+] 从Sharepoint 2007开始,工作流作为一个真正的强有力的工具内置在SharePoint中.你可以通过设计工作流,从而在网站或应用程序中添加自定义逻辑,而且不需要编写任何代码!通过工作流实现业务流程自动化所需的各种功能,从发送通知到创建任务这么简单的事都可以通过工作流完成.还有的很多可能性,许多的功能有

C#WPF 语音开发教程 源代码下载 csdn tts(text to sound) 一步一步 教你制作语音软件 附图和源代码

C#WPF  语音开发教程  一步一步 教你制作语音软件 附图和源代码 效果展示 一 项目准备 1.vs2012开发平台 2.微软的语音软件库 下载:http://download.csdn.net/detail/wyx100/8431269 (含实例项目源代码) 二.开发目标 制作一个语音软件,可以朗读文字: 多个语音库:男音和女音.支持英文和中文朗读: 支持选择播放设备 支持朗读语速选择 支持音量选择 三 开发过程 1.新建WpfSpeechDemo工程 文件(vs开发平台左上角)----新

一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)

这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际App. 在实现的过程中,会有很多困难,还会发现有一些功能目前缺乏组件支持而无法实现,也会碰见各种移动开发中都会碰到的常见技术问题.一步一步的操作和问题的解决可以让开发者直观的了解通过DeviceOne如何开发一个实际App,也可以了解移动开发本身的很多技术细节,可以让App开发者少走很多弯路. 这

一步一步开发呼叫中心

最近两个月,每天熬夜到凌晨5点,睡3个小时,继续奋战.少年,你这么拼,你未出生的女儿知道么?(其实我也不确定是不是女儿,由于个人最喜欢女儿,姑且当我那还有1个多月出来见老爸的宝贝是个女儿吧!) 唉,创业难,做苦逼程序员更难,做没有任何指导要一个人进入一个新的领域的程序员更难! 2014年做了好多事情,前两个月一直忙,也没有花时间来总结自己的得失,这两天公司终于没啥事了,来写下开发呼叫中心的心得体会. 事先声明: 1.本文为个人总结文章,非开源项目,核心的呼叫中心源码不会开放,总结的是开发思路 2

一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版

上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文件.便利性不是很高. 那么有么有办法能做到动态实时更新呢???? 官方提供了这两个对象,动态编译源文件. 提供对 C# 代码生成器和代码编译器的实例的访问. CSharpCodeProvider 提供一下方法加载源文件, // 基于包含在 System.CodeDom.CodeCompileUnit

跟我一步一步开发自己的Openfire插件

http://www.blogjava.net/hoojo/archive/2013/03/07/396146.html 跟我一步一步开发自己的Openfire插件 这篇是简单插件开发,下篇聊天记录插件. 开发环境: System:Windows WebBrowser:IE6+.Firefox3+ JavaEE Server:tomcat5.0.2.8.tomcat6 IDE:eclipse.MyEclipse 8 开发依赖库: Jdk1.6.jasper-compiler.jar.jasper