任务三计算机网络实验I P数据报捕获与分析任务三网络编程一、实验目的捕获本机网卡的IP包,对捕获的IP包进行解析。
要求必须输出以下字段:版本号、总长度、标志位、片偏移、协议、源地址和目的地址。
二、实验环境平台:Windows编程环境:VC 6.0语言:C++三、实验原理3.1 数据报格式以太帧由一个包含三个字段的帧头开始,前两个字段包含了物理地址,各六个字节,头部的第三个字段包含了 16 位的以太帧类型,帧头后面是数据区。
根据帧类型可以判断是哪种数据包,一般常用的有 0X0080(IP 数据包)、0X0806(ARP 请求/应答)和 0X8035(RARP 请求/应答)三种类型。
TCP/IP 协议簇中位于网络层的协议,也是最为核心的协议。
所有的 TCP, UDP, ICMP及 IGMP 数据都以 IP 数据报格式传输。
IP 协议提供了无连接的、不可靠的数据传输服务。
同时IP 协议的一个重要功能是为网络上的包传递提供路由支持。
TCP/IP 协议使用 IP 数据报这个名字来指代一个互联网数据包。
IP 数据报由两部分组成,前面的头部和后面的数据区,头部含有描述该数据报的信息,包括源 IP 地址和目的 IP 地址等。
在 IP 数据报的报头中的众多信息可根据协议类型字段区分出该数据包的类型,常用的有TCP 包、 UDP 包、 ICMP 包等,各格式分别如下所示:IP数据报格式TCP数据报格式ICMP数据报格式UDP数据报格式3.2 捕获数据包方法目前常用的捕获数据包的方法有原始套接字、LibPcap、WinPcap和JPcap 等方法。
本次实验选用套接字方法。
套接字是网络应用编程接口。
应用程序可以使用它进行网络通信而不需要知道底层发生的细节。
有时需要自己生成一些定制的数据包或者功能并希望绕开Socket提供的功能,原始套接字(RawSocket)满足了这样的要求。
原始套接字能够生成自己的数据报文,包括报头和数据报本身的内容。
通过原始套接字,可以更加自如地控制Windows下的多种协议,而且能够对网络底层的传输机制进行控制。
网络数据包截获机制一般指通过截获整个网络的所有信息流,根据信息源主机,目标主机,服务协议端口等信息,简单过滤掉不关心的数据,再将用户感兴趣的数据发送给更高层的应用程序进行分析。
一般数据包的传输路径依次为网卡、设备驱动层、数据链路层、 IP 层、传输层、最后到达应用程序。
IP 数据包的捕获就是将经过数据链路层的以太网帧拷贝出一个备份,传送给 IP 数据包捕获程序进行相关的处理。
IP 数据包的捕获程序一般由数据包捕获函数库和数据包分析器组成。
数据包捕获函数库是一个独立于操作系统的标准捕获函数库。
主要提供一组可用于查找网络接口名称、打开选定的网络接口、初始化、设置包过滤条件、编译过滤代码、捕获数据包等功能函数。
对捕获程序而言,只需要调用数据包捕获函数库的这些函数就能获得所期望的 IP 数据包。
这种捕获程序与数据包捕获函数库分离的机制,使得编写的程序具有很好的可移植性。
IP 数据包捕获程序的核心部分就是数据包分析器。
数据包分析器应具有识别和理解各种协议格式(IP、 TCP、 UCP、 ICMP 协议)和帧格式的能力,并对捕获的数据进行分析和统计处理。
编写数据包捕获程序的主要工作就是如何实现数据包分析器的功能。
3.3 数据包捕获与解析的程序设计首先对以太网帧头进行结构体定义,总共有以下 13 项内容:Version、HeadLen、ServiceType、 TotalLen、Identifier、Flags、FragOffset、TimeToLive、Protocol、HeadChecksum、SourceAddr、DestinAddr、Options。
根据数据包的捕获机制,分别对以上 13 个内容编写捕获的 C 语言程序,进行一一捕获,通过开始的运行程序中运行编译程序后所得到的.exe 文件,就可以看到捕获到的信息。
捕获成功之后,最后将其各个信息进行解析,并写到一个文件之中。
以上各个程序的编写都是在 Visual Stdio C++ 6.0 编译器中完成。
3.4 网卡设置为了获取网络中的IP数据包,必须对网卡进行编程,在这里使用套接字进行编程。
但是,在通常情况下,网络通信的套接字程序只能响应与自己硬件地址相匹配的数据包或是以广播形式发出的数据包。
对于其他形式的数据包,如已到达网络接口,但却不是发送到此地址的数据包,网络接口在骓投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取与自己无关的数据包。
要想获取网络设备的所有数据包,就需要将网卡设置为混杂模式。
四、实验结果及分析程序运行结果截图:附件:网络数据包捕获与解析的完整程序#include <iostream>#include <winsock2.h>#include <ws2tcpip.h>#include <cstdlib>#include <fstream>#include <string>#pragma comment(lib, "ws2_32")#define IO_RCVALL _WSAIOW(IOC_VENDOR, 1)using namespace std;typedef struct IP_HEAD{union{unsigned char Version; //Version(4)unsigned char HeadLen; //Header Length(4) };unsigned char ServiceType; //Type of Servics(8)unsigned short TotalLen; //Total Length(16)unsigned short Identification; //Identification(16)union{unsigned short Flags; //IP Flags(3)unsigned short FragOffset; //Fragment Offset(13) };unsigned char TimeToLive; //TTL(8)unsigned char Protocol; //Protocol(8)unsigned short HeadChecksum; //Header Checksum(16)unsigned int SourceAddr; //Source Address(32)unsigned int DestinAddr; //Destination Address(32)unsigned char Options; //IP Options} ip_head;void main(){WSADATA WSAData;if(WSAStartup(MAKEWORD(2,2), &WSAData) != 0){//初始化cout<<"Init fails!"<<endl;return;}/****************************数据包的捕获*********************************/SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); //抓捕IP数据报bool flag = true;setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)); //设置IP头操作选项char hostName[128];gethostname(hostName, 100);hostent* pHostIp = gethostbyname(hostName);sockaddr_in host_addr;host_addr.sin_family = AF_INET;host_addr.sin_port = htons(6000);host_addr.sin_addr = *(in_addr*)pHostIp->h_addr_list[0];bind(sock, (PSOCKADDR)&host_addr, sizeof(host_addr)); //把sockRaw绑定到本地网卡上DWORD dwBufferLen[10];DWORD dwBufferInLen = 1;DWORD dwBytesReturned = 0;WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL);//接受所有的数据char buffer[65535];ip_head ip;int packsum = 2;for(int i=0; i<packsum; i++){if(recv(sock, buffer, 65535, 0)>0){ip = *(ip_head*)buffer;cout<<"Version:"<<inet_ntoa(*(in_addr*)&ip.Version)<<endl;cout<<"HeadLen:"<<inet_ntoa(*(in_addr*)&ip.HeadLen)<<endl;cout<<"ServiceType: "<<inet_ntoa(*(in_addr*)&ip.ServiceType)<<endl;cout<<"TotalLen:"<<inet_ntoa(*(in_addr*)&ip.TotalLen)<<endl;cout<<"Identification:"<<inet_ntoa(*(in_addr*)&ip.Identification)<<endl;cout<<"Flags:"<<inet_ntoa(*(in_addr*)&ip.Flags)<<endl;cout<<"FragOffset: "<<inet_ntoa(*(in_addr*)&ip.FragOffset)<<endl;cout<<"TimeToLive: "<<inet_ntoa(*(in_addr*)&ip.TimeToLive)<<endl;cout<<"Protocol:"<<inet_ntoa(*(in_addr*)&ip.Protocol)<<endl;cout<<"HeadChecksum:"<<inet_ntoa(*(in_addr*)&ip.HeadChecksum)<<endl;cout<<"SourceAddr:"<<inet_ntoa(*(in_addr*)&ip.SourceAddr)<<endl;cout<<"DestinAddr:"<<inet_ntoa(*(in_addr*)&ip.DestinAddr)<<endl;cout<<"Options:"<<inet_ntoa(*(in_addr*)&ip.Options)<<endl<<endl;}}/*****************************数据包的解析********************************///string str = inet_ntoa(*(in_addr*)&ip.SourceAddr);string ver = inet_ntoa(*(in_addr*)&ip.Version);string str1= inet_ntoa(*(in_addr*)&ip.HeadLen);string str2= inet_ntoa(*(in_addr*)&ip.ServiceType);string str3 = inet_ntoa(*(in_addr*)&ip.TotalLen);string str4 = inet_ntoa(*(in_addr*)&ip.Identification);string str5 = inet_ntoa(*(in_addr*)&ip.Flags);string str6 = inet_ntoa(*(in_addr*)&ip.FragOffset);string str7 = inet_ntoa(*(in_addr*)&ip.TimeToLive);string str8 = inet_ntoa(*(in_addr*)&ip.Protocol);string str9 = inet_ntoa(*(in_addr*)&ip.HeadChecksum);string str10= inet_ntoa(*(in_addr*)&ip.SourceAddr);string str11 = inet_ntoa(*(in_addr*)&ip.DestinAddr);string str12 = inet_ntoa(*(in_addr*)&ip.Options);fstream outfile;outfile.open("d:\\aa.dat", ios::out|ios::binary|ios::trunc);//ios::in|outfile.write(ver.c_str(), ver.length()+3);outfile.write(str1.c_str(), str1.length()+3);outfile.write(str2.c_str(), str2.length()+3);outfile.write(str3.c_str(), str3.length()+3);outfile.write(str4.c_str(), str4.length()+3);outfile.write(str6.c_str(), str6.length()+3);outfile.write(str7.c_str(), str7.length()+3);outfile.write(str8.c_str(), str8.length()+3);outfile.write(str9.c_str(), str9.length()+3);outfile.write(str10.c_str(), str10.length()+3);outfile.write(str11.c_str(), str11.length()+3);outfile.write(str12.c_str(), str12.length()+3);outfile.close();system("pause");}。