一步一步开发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上
解析函数的代码如下:
- /*pkt为网络中捕获的包,data为要存为本机上的数据*/
- /*分析链路层*/
- int analyze_frame(const u_char * pkt,struct datapkt * data,struct pktcount *npacket)
- {
- int i;
- struct ethhdr *ethh = (struct ethhdr*)pkt;
- data->ethh = (struct ethhdr*)malloc(sizeof(struct ethhdr));
- if(NULL == data->ethh)
- return -1;
- for(i=0;i<6;i++)
- {
- data->ethh->dest[i] = ethh->dest[i];
- data->ethh->src[i] = ethh->src[i];
- }
- npacket->n_sum++;
- /*由于网络字节顺序原因,需要对齐*/
- data->ethh->type = ntohs(ethh->type);
- //处理ARP还是IP包?
- switch(data->ethh->type)
- {
- case 0x0806:
- return analyze_arp((u_char*)pkt+14,data,npacket); //mac 头大小为14
- break;
- case 0x0800:
- return analyze_ip((u_char*)pkt+14,data,npacket);
- break;
- case 0x86dd:
- return analyze_ip6((u_char*)pkt+14,data,npacket);
- return -1;
- break;
- default:
- npacket->n_other++;
- return -1;
- break;
- }
- return 1;
- }
- /*分析网络层:ARP*/
- int analyze_arp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- int i;
- struct arphdr *arph = (struct arphdr*)pkt;
- data->arph = (struct arphdr*)malloc(sizeof(struct arphdr));
- if(NULL == data->arph )
- return -1;
- //复制IP及MAC
- for(i=0;i<6;i++)
- {
- if(i<4)
- {
- data->arph->ar_destip[i] = arph->ar_destip[i];
- data->arph->ar_srcip[i] = arph->ar_srcip[i];
- }
- data->arph->ar_destmac[i] = arph->ar_destmac[i];
- data->arph->ar_srcmac[i]= arph->ar_srcmac[i];
- }
- data->arph->ar_hln = arph->ar_hln;
- data->arph->ar_hrd = ntohs(arph->ar_hrd);
- data->arph->ar_op = ntohs(arph->ar_op);
- data->arph->ar_pln = arph->ar_pln;
- data->arph->ar_pro = ntohs(arph->ar_pro);
- strcpy(data->pktType,"ARP");
- npacket->n_arp++;
- return 1;
- }
- /*分析网络层:IP*/
- int analyze_ip(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- int i;
- struct iphdr *iph = (struct iphdr*)pkt;
- data->iph = (struct iphdr*)malloc(sizeof(struct iphdr));
- if(NULL == data->iph)
- return -1;
- data->iph->check = iph->check;
- npacket->n_ip++;
- /*for(i = 0;i<4;i++)
- {
- data->iph->daddr[i] = iph->daddr[i];
- data->iph->saddr[i] = iph->saddr[i];
- }*/
- data->iph->saddr = iph->saddr;
- data->iph->daddr = iph->daddr;
- data->iph->frag_off = iph->frag_off;
- data->iph->id = iph->id;
- data->iph->proto = iph->proto;
- data->iph->tlen = ntohs(iph->tlen);
- data->iph->tos = iph->tos;
- data->iph->ttl = iph->ttl;
- data->iph->ihl = iph->ihl;
- data->iph->version = iph->version;
- //data->iph->ver_ihl= iph->ver_ihl;
- data->iph->op_pad = iph->op_pad;
- int iplen = iph->ihl*4; //ip头长度
- switch(iph->proto)
- {
- case PROTO_ICMP:
- return analyze_icmp((u_char*)iph+iplen,data,npacket);
- break;
- case PROTO_TCP:
- return analyze_tcp((u_char*)iph+iplen,data,npacket);
- break;
- case PROTO_UDP:
- return analyze_udp((u_char*)iph+iplen,data,npacket);
- break;
- default :
- return-1;
- break;
- }
- return 1;
- }
- /*分析网络层:IPV6*/
- int analyze_ip6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- int i;
- struct iphdr6 *iph6 = (struct iphdr6*)pkt;
- data->iph6 = (struct iphdr6*)malloc(sizeof(struct iphdr6));
- if(NULL == data->iph6)
- return -1;
- npacket->n_ip6++;
- data->iph6->version = iph6->version;
- data->iph6->flowtype = iph6->flowtype;
- data->iph6->flowid = iph6->flowid;
- data->iph6->plen = ntohs(iph6->plen);
- data->iph6->nh = iph6->nh;
- data->iph6->hlim =iph6->hlim;
- for(i=0;i<16;i++)
- {
- data->iph6->saddr[i] = iph6->saddr[i];
- data->iph6->daddr[i] = iph6->daddr[i];
- }
- switch(iph6->nh)
- {
- case 0x3a:
- return analyze_icmp6((u_char*)iph6+40,data,npacket);
- break;
- case 0x06:
- return analyze_tcp((u_char*)iph6+40,data,npacket);
- break;
- case 0x11:
- return analyze_udp((u_char*)iph6+40,data,npacket);
- break;
- default :
- return-1;
- break;
- }
- //npacket->n_ip6++;
- //strcpy(data->pktType,"IPV6");
- return 1;
- }
- /*分析传输层:ICMP*/
- int analyze_icmp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- struct icmphdr* icmph = (struct icmphdr*)pkt;
- data->icmph = (struct icmphdr*)malloc(sizeof(struct icmphdr));
- if(NULL == data->icmph)
- return -1;
- data->icmph->chksum = icmph->chksum;
- data->icmph->code = icmph->code;
- data->icmph->seq =icmph->seq;
- data->icmph->type = icmph->type;
- strcpy(data->pktType,"ICMP");
- npacket->n_icmp++;
- return 1;
- }
- /*分析传输层:ICMPv6*/
- int analyze_icmp6(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- int i;
- struct icmphdr6* icmph6 = (struct icmphdr6*)pkt;
- data->icmph6 = (struct icmphdr6*)malloc(sizeof(struct icmphdr6));
- if(NULL == data->icmph6)
- return -1;
- data->icmph6->chksum = icmph6->chksum;
- data->icmph6->code = icmph6->code;
- data->icmph6->seq =icmph6->seq;
- data->icmph6->type = icmph6->type;
- data->icmph6->op_len = icmph6->op_len;
- data->icmph6->op_type = icmph6->op_type;
- for(i=0;i<6;i++)
- {
- data->icmph6->op_ethaddr[i] = icmph6->op_ethaddr[i];
- }
- strcpy(data->pktType,"ICMPv6");
- npacket->n_icmp6++;
- return 1;
- }
- /*分析传输层:TCP*/
- int analyze_tcp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- struct tcphdr *tcph = (struct tcphdr*)pkt;
- data->tcph = (struct tcphdr*)malloc(sizeof(struct tcphdr));
- if(NULL == data->tcph)
- return -1;
- data->tcph->ack_seq = tcph->ack_seq;
- data->tcph->check = tcph->check;
- data->tcph->doff = tcph->doff;
- data->tcph->res1 = tcph->res1;
- data->tcph->cwr = tcph->cwr;
- data->tcph->ece = tcph->ece;
- data->tcph->urg = tcph->urg;
- data->tcph->ack = tcph->ack;
- data->tcph->psh = tcph->psh;
- data->tcph->rst = tcph->rst;
- data->tcph->syn = tcph->syn;
- data->tcph->fin = tcph->fin;
- //data->tcph->doff_flag = tcph->doff_flag;
- data->tcph->dport = ntohs(tcph->dport);
- data->tcph->seq = tcph->seq;
- data->tcph->sport = ntohs(tcph->sport);
- data->tcph->urg_ptr = tcph->urg_ptr;
- data->tcph->window= tcph->window;
- data->tcph->opt = tcph->opt;
- /////////////////////*不要忘记http分支*/////////////////////////
- if(ntohs(tcph->dport) == 80 || ntohs(tcph->sport)==80)
- {
- npacket->n_http++;
- strcpy(data->pktType,"HTTP");
- }
- else{
- npacket->n_tcp++;
- strcpy(data->pktType,"TCP");
- }
- return 1;
- }
- /*分析传输层:UDP*/
- int analyze_udp(const u_char* pkt,datapkt *data,struct pktcount *npacket)
- {
- struct udphdr* udph = (struct udphdr*)pkt;
- data->udph = (struct udphdr*)malloc(sizeof(struct udphdr));
- if(NULL == data->udph )
- return -1;
- data->udph->check = udph->check;
- data->udph->dport = ntohs(udph->dport);
- data->udph->len = ntohs(udph->len);
- data->udph->sport = ntohs(udph->sport);
- strcpy(data->pktType,"UDP");
- npacket->n_udp++;
- return 1;
- }
一步一步开发sniffer(Winpcap+MFC)(五)莫道无人能识君,其实我懂你的心——解析数据包(转)的更多相关文章
- c语言Winpcap编程构造并接收解析arp包
/* 程序功能: 1.构造arp包,并发送.程序参数顺序:源IP.目的IP.mac地址.flag 2.获取网络中的ARP数据包,解析数据包的内容.程序参数:日志文件名 winpacp中文技术文档(基本 ...
- 一步一步开发Game服务器(四)地图线程
时隔这么久 才再一次的回归正题继续讲解游戏服务器开发. 开始讲解前有一个问题需要修正.之前讲的线程和定时器线程的时候是分开的. 但是真正地图线程与之前的线程模型是有区别的. 为什么会有区别呢?一个地图 ...
- 一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版
上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...
- 一步一步了解Cocos2dx 3.0 正式版本开发环境搭建(Win32/Android)
cocos2d-x 3.0发布有一段时间了,作为一个初学者,我一直觉得cocos2d-x很坑.每个比较大的版本变动,都会有不一样的项目创建方式,每次的跨度都挺大…… 但是凭心而论,3.0RC版本开始 ...
- 一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)
这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...
- 跟我一步一步开发自己的Openfire插件
http://www.blogjava.net/hoojo/archive/2013/03/07/396146.html 跟我一步一步开发自己的Openfire插件 这篇是简单插件开发,下篇聊天记录插 ...
- 一步一步构建手机WebApp开发——页面布局篇
继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...
- xmppmini 项目详解:一步一步从原理跟我学实用 xmpp 技术开发 2.登录的实现
第二章登录的实现 金庸<倚天屠龙记> 张三丰缓缓摇头,说道:“少林派累积千年,方得达成这等绝技,决非一蹴而至,就算是绝顶聪明之人,也无法自创.”他顿了一顿,又道:“我当年在少林寺中住过,只 ...
- 一步一步开发Game服务器(一)
什么是服务器?对于很多人来说也许只是简单成为在服务器端运行的程序的确如此,服务器通常意义就是说在服务器端运行的程序而已.那么我们怎么理解和分析游戏服务器哪? 传统意义上来说,程序运行后,正常流程, 启 ...
随机推荐
- java多线程快速入门(四)
通过匿名内部类的方法创建多线程 package com.cppdy; //通过匿名内部类的方法创建多线程 public class ThreadDemo2 { public static void m ...
- python 全栈开发,Day61(库的操作,表的操作,数据类型,数据类型(2),完整性约束)
昨日内容回顾 一.回顾 定义:mysql就是一个基于socket编写的C / S架构的软件 包含: ---服务端软件 - socket服务端 - 本地文件操作 - 解析指令(mysql语句) ---客 ...
- python 全栈开发,Day19(组合,组合实例,初识面向对象小结,初识继承)
一.组合 表示的一种什么有什么的关系 先来说一下,__init__的作用 class Dog: def __init__(self, name, kind, hp, ad): self.name = ...
- 《剑指offer》-前n项和不准用通解和各种判断
题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 这题目简直没事找事...为啥这么说,因为没有限 ...
- js获取精确的元素宽高(普通获取高度会有误差)
当js获取元素宽高时, 并不是一个精确的数字,如果想获取真正的宽高大致方法如下 var oStyle = obj.currentStyle ? obj.currentStyle : window.ge ...
- Java编程的逻辑 (12) - 函数调用的基本原理
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- 007 关于Spark下的第二种模式——standalone搭建
一:介绍 1.介绍standalone Standalone模式是Spark自身管理资源的一个模式,类似Yarn Yarn的结构: ResourceManager: 负责集群资源的管理 NodeMan ...
- 'utf-8' codec can't decode byte 0xc8 in position 0
今天学习python中使用jieba库,遇到了错误:“UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 0: i ...