实验四编写协议解析器程序
一、实验要求及目的
使用libpcap/winpcap进行网络抓包,并解析网络数据包的各层首部字段。
通过编写程序,捕获一段时间内以本机为源地址或目的地址的IP数据包,统计IP数据包的信息,解析首部字段,帮助加深对IP协议的工作原理和工作过程的认识以及掌握winpcap抓包原理。
二、实验运行环境
本实验是是用winpcap进行网络抓包,基于windows系统,下载WpdPack 4.1.2安装包,在Visio stdio 2012上配置winpcap抓包环境,再编写C++代码实现网络抓包。
三、实验原理
TCP/IP协议族的分层结构包括应用层,传输层,互联网络层和主机-网络层,其结构如图1所示:
应用层Telnet、TFP、SMTP DNS、TFTP、SNMP
传输层TCP UDP 互联网络层IP
主机-网络层Ethernet,Token Ring,X.25,SLIP,PPP
图1 TCP/IP协议族的分层结构
其中IP协议是保证以太网正常运行的最重要的协议之一,只要用于负责IP 寻址,路由选择和IP数据报的分割与组装。
IP协议是直接位于数据链路层之上,负责将源主机的报文分组发送到目的主机。
IP协议是一种不可靠,无连接的数据报传送服务协议,它提供的是一种“尽力而为”的服务。
为了向传输层屏蔽的通信子网的差异,IP协议制订了统一的IP数据报格式。
IP数据报的长度是可变的,它分为报头和数据两个部分。
基本的IP报头是20B.选项字段的长度范围是0—40B,所以IP数据报报头的长度是范围是20-60B。
IPV4 IP数据报的结构如图2所示:
图2 IP数据包格式
IP首部封装具体解释如下:
(1)版本占4位,是指IP协议的版本。
通信双方使用的IP协议版本必须一致。
目前广泛使用的IP协议版本号为4(即IPv4)
(2)首部长度占4位,可表示的最大十进制数值是15。
这个字段所表示数的单位是32位字长(1个32位字长是4字节),因此,当IP的首部长度为1111时(即十进制的15),首部长度就达到60字节。
当IP分组的首部长度不是4字节的整数倍时,必须利用最后的填充字段加以填充。
因此数据部分永远在4字节的整数倍开始,这样在实现IP协议时较为方便。
首部长度限制为60字节的缺点是有时可能不够用。
但这样做是希望用户尽量减少开销。
最常用的首部长度就是20字节(即首部长度为0101),这时不使用任何选项。
(3)区分服务占8位,用来获得更好的服务。
这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。
1998年IETF把这个字段改名为区分服务DS(Differentiated Services)。
只有在使用区分服务时,这个字段才起作用。
(4)总长度总长度指首部和数据之和的长度,单位为字节。
总长度字段为16位,因此数据报的最大长度为216-1=65535字节。
(5)标识(identification) 占16位。
IP软件在存储器中维持一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。
但这个“标识”并不
是序号,因为IP是无连接服务,数据报不存在按序接收的问题。
当数据报由于长度超过网络的MTU而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。
相同的标识字段的值使分片后的各数据报片最后能正确地重装成为原来的数据报。
(6)标志(flag) 占3位,但目前只有2位有意义。
标志字段中的最低位记为MF(More Fragment)。
MF=1即表示后面“还有分片”的数据报。
MF=0表示这已是若干数据报片中的最后一个。
标志字段中间的一位记为DF(Don’t Fragment),意思是“不能分片”。
只有当DF=0时才允许分片。
(7)片偏移占13位。
片偏移指出:较长的分组在分片后,某片在原分组中的相对位置。
也就是说,相对用户数据字段的起点,该片从何处开始。
片偏移以8个字节为偏移单位。
这就是说,每个分片的长度一定是8字节(64位)的整数倍。
(8)生存时间占8位,生存时间字段常用的的英文缩写是TTL(Time To Live),表明是数据报在网络中的寿命。
由发出数据报的源点设置这个字段。
其目的是防止无法交付的数据报无限制地在因特网中兜圈子,因而白白消耗网络资源。
最初的设计是以秒作为TTL的单位。
每经过一个路由器时,就把TTL减去数据报在路由器消耗掉的一段时间。
若数据报在路由器消耗的时间小于1秒,就把TTL值减1。
当TTL值为0时,就丢弃这个数据报。
(9)协议占8位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据部分上交给哪个处理过程。
(10)首部检验和占16位。
这个字段只检验数据报的首部,但不包括数据部分。
这是因为数据报每经过一个路由器,路由器都要重新计算一下首部检验和(一些字段,如生存时间、标志、片偏移等都可能发生变化)。
不检验数据部分可减少计算的工作量。
(11)源IP地址占32位。
表示发送数据报的源主机的IP地址
(12)目的IP地址占32位。
本实验的IP数据包首部定义如下:
struct ip_header
{
#if defined(WORDS_BIENDIAN)
u_int8_t ip_version:4,
ip_header_length:4;
#else
u_int8_t ip_header_length:4,
ip_version:4;
#endif
u_int8_t ip_tos;
u_int16_t ip_length;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_protocol;
u_int16_t ip_checksum;
struct in_addr ip_souce_address;
struct in_addr ip_destination_address;
};
捕获IP数据包,一般借助winpcap或libpcap提供的API对网络数据包进行抓取。
winpcap是为windows开发环境提供的库函数,而libpcap则是为Linux 开发环境提供的库函数。
它们都是一个强大的网络开发库,可以实现许多功能,如获取可用的网络适配器、获取指定适配器信息(比如名称和描述信息)、捕获指定网卡的数据封包、发送数据封包、过滤捕获的包以获取特定包等。
两者提供的接口基本一致,只是某些函数名略有不同。
在使用前必须将winpcap或libpcap 安装在系统上,在使用时必须在工程中加入对应的开发包并在程序中声明。
在抓取数据包后,对其进行分析,要参考数据包的格式,所以数据包的格式是相当重要的。
在抓包时,首先是获得链路层的帧,根据帧头可以获得源mac 和目的mac以及上层的协议。
根据帧头的长度将指针往后移,然后可以获得IP数据报的头部指针,根据报头信息可以获得源IP、目的IP、上层协议、头部长度、总长度等信息。
四、实验编程思路
在本次实验编程中使用winpcap捕获IP数据包的过程如下:
首先获取网络设备的列表,这一步骤通过函数pcap_lookupdev()来实现,第二步是用函数pcap_open_live()打开找到的网卡设备。
pcap_open_live()中有一个参数为超时返回的间隔,通常设为500ms即可。
第三步是用pcap_compile()编译抓包的过滤规则。
第四步用pcap_compile()来编译抓包的过滤规则,最后pcap_loop()开始抓包。
最后用函数ip_protool_packet_callback以及函数ethernet_protocol_packet_callback来输出抓包后分析的首部信息。
五、程序运行结果及分析
本次实验一共抓取5个数据包,分析出了数据包的长度,MAC帧源地址,目的地址以及的分析出来上层协议是IP协议。
解析IP数据包的首部,输出了首部的详细信息。
从捕获的第一个网络数据包来看,首先这是一个0800的以太网类型,从上面的实验原理,可以看出这是一个IP数据包。
代码分析出了IP数据包的MAC帧源地址,目的地址。
IP数据包解析出来的首部长度是6,也即4*6=24位。
符合首部长度的范围定义,其次解析出了版本号,总长度,标识等详细信息,从以上原理可以得出抓包及分析正确。