前文已经讲过,解析数据包主要通过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. python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  2. python 全栈开发,Day43(引子,协程介绍,Greenlet模块,Gevent模块,Gevent之同步与异步)

    昨日内容回顾 I/O模型,面试会问到I/O操作,不占用CPU.它内部有一个专门的处理I/O模块.print和写log 属于I/O操作,它不占用CPU 线程GIL保证一个进程中的多个线程在同一时刻只有一 ...

  3. WaitForMultipleObjects返回0xffffffff

    DWORD ret; ; HANDLE handle[THREAD_NUM]; ; i < THREAD_NUM; i++) handle[i] = (HANDLE)_beginthreadex ...

  4. ERP发货系统的修改(四十三)

    产品添加批号后相应修改产品库存表中对应批次产品的数量: /// <summary> /// 产品添加批号后相应修改产品库存表中对应批次产品的数量 /// </summary> ...

  5. asp.net core 微信公众号支付(扫码支付,H5支付,公众号支付,app支付)之3

    在微信公众号中访问手机网站,当需要调用支付时候无法使用H5支付,只有使用微信公众号支付,使用公众号支付用户必须关注该公众号同时该公众号必须开通公众号支付功能. 1.获取用户的OpenId ,参考之前写 ...

  6. mysql数据库备份 mysqldump

    一.--all-databases /application/mysql3307/bin/mysqldump -uroot -S /application/mysql3307/logs/mysql.s ...

  7. 2.2博客系统 |FileField字段 |Media配置

    基于forms组件和Ajax实现注册功能 1 基于forms组件设计注册页面 --点击头像 === 点击input --头像预览: 修改用户选中的文件对象:获取文件对象的路径:修改img的src属性, ...

  8. 3.Django| 视图层| 模板层

    1.视图函数 文件在view_demo 一个视图函数简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XM ...

  9. 009 搭建Spark的maven本地windows开发环境以及测试

    在看完下面的细节之后,就会发现,spark的开发,只需要hdfs加上带有scala的IDEA环境即可.  当run运行程序时,很快就可以运行结束. 为了可以看4040界面,需要将程序加上暂定程序,然后 ...

  10. CentOS下生成密钥对(公钥、私钥)

    1.公钥.私钥简述: 假设数据传输方A向数据接收方B传输数据(以A为服务器,B为客户端为例).现在B有一对密钥对(公钥和私钥),B将公钥发送给A,A通过公钥加密后将数据传给B,B收到数据后利用手里的私 ...