前文已经讲过,解析数据包主要通过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上

解析函数的代码如下:

    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. }

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

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

    /* 程序功能: 1.构造arp包,并发送.程序参数顺序:源IP.目的IP.mac地址.flag 2.获取网络中的ARP数据包,解析数据包的内容.程序参数:日志文件名 winpacp中文技术文档(基本 ...

  2. 一步一步开发Game服务器(四)地图线程

    时隔这么久 才再一次的回归正题继续讲解游戏服务器开发. 开始讲解前有一个问题需要修正.之前讲的线程和定时器线程的时候是分开的. 但是真正地图线程与之前的线程模型是有区别的. 为什么会有区别呢?一个地图 ...

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

    上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...

  4. 一步一步了解Cocos2dx 3.0 正式版本开发环境搭建(Win32/Android)

    cocos2d-x 3.0发布有一段时间了,作为一个初学者,我一直觉得cocos2d-x很坑.每个比较大的版本变动,都会有不一样的项目创建方式,每次的跨度都挺大…… 但是凭心而论,3.0RC版本开始 ...

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

    这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...

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

    http://www.blogjava.net/hoojo/archive/2013/03/07/396146.html 跟我一步一步开发自己的Openfire插件 这篇是简单插件开发,下篇聊天记录插 ...

  7. 一步一步构建手机WebApp开发——页面布局篇

    继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...

  8. xmppmini 项目详解:一步一步从原理跟我学实用 xmpp 技术开发 2.登录的实现

    第二章登录的实现 金庸<倚天屠龙记> 张三丰缓缓摇头,说道:“少林派累积千年,方得达成这等绝技,决非一蹴而至,就算是绝顶聪明之人,也无法自创.”他顿了一顿,又道:“我当年在少林寺中住过,只 ...

  9. 一步一步开发Game服务器(一)

    什么是服务器?对于很多人来说也许只是简单成为在服务器端运行的程序的确如此,服务器通常意义就是说在服务器端运行的程序而已.那么我们怎么理解和分析游戏服务器哪? 传统意义上来说,程序运行后,正常流程, 启 ...

随机推荐

  1. C++ code:向量操作之添加元素

    读入一个文件aaa.txt的数据到向量中,文件中是一些整数(个数未知).要判断向量中的元素有多少个两两相等的数对. 代码如下: #include<iostream> #include< ...

  2. 大坑啊oracle的隐式转换

    (25)禁止使用属性隐式转换 解读:SELECT uid FROM t_user WHERE phone=13812345678 会导致全表扫描,而不能命中phone索引,猜猜为什么?(这个线上问题不 ...

  3. cf Queries on a String

    #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define ...

  4. Linux下配置自动更新时间

    1,修正本地时区及ntp服务 [root@VM_0_13_centos ~]# yum -y install ntp [root@VM_0_13_centos ~]# rm -rf /etc/loca ...

  5. windows Service程序的安装、启动、卸载命令

    安装:%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe ServiceTest.exe 启动:Net Start serv ...

  6. thinkphp错误提示:系统发生错误

    下载最新版本3.1.3,定义了一个应用,进入应用的config.php,在里面添加数据库类链接信息,在控制器里面M()一个表,访问控制器方法提示:系统发生错误.如果使用连接字符串DSN方式,调用M() ...

  7. AngularJS+Node.js+socket.io 开发在线聊天室

    所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...

  8. #6【bzoj4321】queue2 dp

    题目描述 n 个沙茶,被编号 1~n.排完队之后,每个沙茶希望,自己的相邻的两人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行:  现在想知道,存在多少方案满足沙茶们如此不苛刻的条件.  ...

  9. 046 hiveserver2以及beeline客户端的使用

    一:开启服务 1.启动前端的hiveserver2 按住ctrl+c就可以结束这个服务. 2.怎么知道已经开启的服务 如果进程在后台,可以查出来,kill这些进程. 3.后端开启服务 二:beelin ...

  10. [OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (二)

    部分 V图像特征提取与描述 OpenCV-Python 中文教程(搬运)目录 34 角点检测的 FAST 算法 目标 • 理解 FAST 算法的基础 • 使用 OpenCV 中的 FAST 算法相关函 ...