计算机网络课设IP数据包的捕获.docx
《计算机网络课设IP数据包的捕获.docx》由会员分享,可在线阅读,更多相关《计算机网络课设IP数据包的捕获.docx(17页珍藏版)》请在冰点文库上搜索。
![计算机网络课设IP数据包的捕获.docx](https://file1.bingdoc.com/fileroot1/2023-7/2/da677a0e-31c8-42e3-968e-25d33def4cad/da677a0e-31c8-42e3-968e-25d33def4cad1.gif)
计算机网络课设IP数据包的捕获
计算机网络
课程设计报告
课程名称:
IP数据包捕获与解析
学号:
1162310120
姓名:
授课班号:
284101
年级专业:
11级通信工程
指导老师:
邓志祥
目录
目录
一、设计背景3
1.开发背景3
2.需求分析3
3.可行性分析3
二、设计目标3
1.IP数据包各个部分3
2.基本要求3
三、系统设计3
1.系统功能结构3
2.设计流程图3
3.具体功能实现3
4.实验结果3
四、实验心得6
五、附录7
1.参考文献7
2.实验代码7
一、设计背景
1.开发背景
计算机网络是计算机技术与通信技术紧密结合的产物,网络技术队信息产业的发展产生深远的影响,而且将发挥越来越大的作用。
本章在介绍网络形成于发展历史的基础上,对网络定义、分类与拓扑构型等问题进行了系统的讨论,并对网络的应用、网络技术的研究与发展进行了探讨,以帮助人们对网络技术与应用有一个全面和准确的认识。
IP数据包作为网络层的数据必然要通过帧来传输。
一个数据包可能要通过多个不同的网络。
每一个路由器都要讲接收到的帧进行拆包和处理,然后封装成另外一个帧。
帧的格式与长度取决于网络所采用的协议。
从网络层—数据链路层来看,由于IP数据包的最大长度为65535B,那么它所使用的网络的数据链路层最大传输单元的长度为65535B,那么传输的效率一定会很高。
但是实际上大量使用的网络的最大传输单元长度都比IP数据包的最大长度短。
以太网的MTU长度为1500B,它远小于IP数据包的最大长度。
因此,使用这些网络传输IP数据包时,要对IP数据包进行分成若干较小的片濑传输,这些片的长度小于或等于数据链路层MTU的长度。
2.需求分析
在传输路径中,路由器通常连接多个网络。
不同的网络的数据链路层最大传输单元的长度的可能不同的,因此路由器在接收到数据包,并准备要转发到目的主机时,它必须首先决定使用哪一个接口网络,要决定该网络的数据链路层最大传输单元是否允许该数据包通过。
根据数据包长度来确定是否需要对数据包进行分片。
如果数据包来自一个能够通过较大数据包的局域网,又要通过另一个只能通过较小的数据包的局域网,那么就必须对IP数据包进行分片。
IP数据包分片的方法如下图所示
在IP数据包分片时,首先要确定片长度。
然后将原始IP数据包包括报头分成第1个片。
如果剩下的数据仍然超过长度,那么需要进行第2次分片。
第2个分片数据加上原来的报头,构成第2个片。
这样一直分割到剩下的数据小于片长度为止。
3.可行性分析
经济可行性:
适用本计算机安全系统可提高计算机通信流量分析和管理水平,把大量繁琐工作简单化,能够有效地节省人力物力,并能够准确地进行统计和计算,避免人工统计或计算所带来的差错,保证计算机通信管理高效而有序地进行。
技术可行性:
本系统前台采用Microsoft公司的VisualC++6.0作为主要开发工具;该系统在安全、准确性和运行速度方面都占有一定优势。
二、设计目标
1.IP数据包各个部分
理解IP包的版本、头长度、服务类型、数据包总长度、数据包标识、分段标志、分段偏移量、生存时间、上层协议类型、头校验合、源IP地址和目的IP地址等内容。
2.基本要求
根据IP数据包的标准格式,编写程序捕获IP数据包并进行解析,并将解析后各IP包的头部与数据字段写入输出文件。
三、系统设计
1.系统功能结构
通过对相应的IP数据包进行分析可以得出:
●IP数据包版本的信息
●IP数据包头长度的信息
●IP数据包服务类型的信息
●IP数据包数据包总长度的信息
●IP数据包数据包标识的信息
●IP数据包分段标志的信息
●IP数据包分段偏移值的信息
●IP数据包生存时间的信息
●IP数据包上层协议类型的信息
●IP数据包头校验和的信息
●IP数据包源IP地址的信息
●IP数据包目的IP地址的信息
通过对以上的IP数据报的分析可以得到具体的网络流量状况,并通过对其进行分析,得到当前网络的状况的流量分析结果,从而实现高效的管理。
2.设计流程图
3.具体功能实现
1)网卡设置
为了获取网络中的IP数据包,必须对网卡进行编程,在这里使用套接字(socket)进行编程。
但是,在通常情况下,网络通信的套接字程序只能响应与自己硬件地址相匹配的数据包或是以广播形式发出的数据包。
对于其他形式的数据包,如已到达网络接口,但却不是发送到此地址的数据包,网络接口在骓投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取与自己无关的数据包。
我们要想获取网络设备的所有数据包,就是需要将网卡设置为混杂模式。
2)接受数据包
在程序中可使用recv()函数接收经过的IP包。
该函数有四个参数,第一个参数接收操作所用的套接字描述符;第二个参数接收缓冲区的地址;第三个参数接收缓冲区的大小,也就是所要接收的字节数;第四个参数是一个附加标志,如果对所发送的数据没特殊要求,直接设为0。
因为IP数据包的最大长度是65535B,因此缓冲区的大小不能小于65535B。
设置缓冲区后,可利用循环来反复监听接收IP包,用recv()函数实现接收功能。
3)定义IP头数据结构
没有详细的进行IP数据包的定义,而是利用IP数据包的结构进行调用使得成为一个虚拟的IP数据报。
例如:
ip.Version就是从IP头中取出IP数据源的。
inet_ntoa(*(in_addr*)&ip.DstAddr)就是从IP头中取出目的IP地址的。
后面的依次同理进行求解。
4)IP包解析
解析IP包的字段有两种策略。
针对长度为8位、16位和32位的字段(或子字段)时,可以利用IP-HEADER的成员直接获取。
要解析长度不是8位倍数的字段(或子字段)时,可以利用C语言中的移位以人、及与、或操作完成。
4.实验结果
如上图所示,上半部分是IP数据包各个部分的解析,当IP数据包中协议类型为UDP时在下方会相应显示UDP数据包的解析。
在相应工程文件下有ip.txt文件生成,会存放捕获的数据包。
四、实验心得
通过这一个星期的课程设计,我基本掌握了用套接字编程来实现获取并解析IP数据包的方法。
当然,过程要比想象艰辛得多。
首先是一个设计思想的问题。
众所周知,IP数据报的格式说明了IP协议都具有什么功能。
但是由于在数据报环节知识的薄弱,我特地去图书馆查阅了相关资料,才大致了解了IP数据报的各种位与协议的概念和意义。
进而在脑中才形成了解决问题的理念——网卡可以接收流经其的各种数据报,所以毫无疑问的应当围绕它进行编程实现。
但是这也正是我最迷惑的地方——因为完全不知道如何使用套接字socket()函数——毕竟是以前从未接触过的领域。
后来通过在一些网络编程教材上的了解和与做同类题目同学的讨论,我编程的思路才逐渐清晰起来。
这次课程设计教会我的不仅仅只是如何实践运用与其相关的知识,更重要的是让我懂得个人的实践比单纯的讨论重要,要单纯的讨论比单纯的空想有效。
同时,本次课设也大大提高了我编程的自信,让我感受到了成功的喜悦。
五、附录
1.参考文献
《计算机网络(第四版)》 主编:
谢希仁出版社:
电子工业出版社出版时间:
2004年7月
《计算机网络课程设计》主编:
吴功宜胡晓英张仁何云王宁出版社:
机械工业出版社出版或修订时间:
2005年9月
《计算机网络设计》主编:
易建勋出版社:
人民邮电出版社出版或修订时间:
2007年10月
《计算机网络》主编:
吴功宜出版社:
清华大学出版社
2.实验代码
#include"winsock2.h"
#include"ws2tcpip.h"
#include"iostream.h"
#include"stdio.h"
#pragmacomment(lib,"ws2_32.lib")
typedefstruct_IP_HEADER
{
union
{
BYTEVersion;
BYTEHeadlen;
};
BYTEServiceType;
WORDTotalLen;
WORDID;
union
{
WORDFlags;//标志(前3位)
WORDFragOff;//报头标长(后4位),IP头的长度
};
BYTETTL;
BYTEProtocol;
WORDHdrChksum;//头校验和
DWORDSrcAddr;//源地址
DWORDDstAddr;//目的地址
BYTEOptions;
}IP_HEADER;
typedefstruct_UDP_HEADER
{
unsignedshortsourport;
unsignedshortdestport;
unsignedshortuslength;
unsignedshortchecksum;
}UDP_HEADER,*PUDP_HEADER;
voidgetVersion(BYTEb,BYTE&version)
{
version=b>>4;
}
voidgetIHL(BYTEb,BYTE&total_len)
{
total_len=(b&0x0f)*4;
}
char*parseServiceType_getProcedence(BYTEb)
{
switch(b>>5)
{
case7:
return"NetworkControl";
break;
case6:
return"InternetworkControl";
break;
case5:
return"CRITIC/ECP";
break;
case4:
return"FlashOverride";
break;
case3:
return"Flsah";
break;
case2:
return"Immediate";
break;
case1:
return"Priority";
break;
case0:
return"Routine";
break;
default:
return"Unknow";
break;
}
}
char*parseServiceType_getTOS(BYTEb)
{
b=(b>>1)&0x0f;
switch(b)
{
case0:
return"Normalservice";
break;
case1:
return"Minimizemonetarycost";
break;
case2:
return"Maximizereliability";
break;
case4:
return"Maximizethroughput";
break;
case8:
return"Minimizedelay";
break;
case15:
return"Maximizesecurity";
break;
default:
return"Unknow";
}
}
voidgetFlags(WORDw,BYTE&DF,BYTE&MF)
{
shortflags_host=ntohs(w);
DF=(flags_host>>14)&0x01;
MF=(flags_host>>13)&0x01;
}
voidgetFragOff(WORDw,WORD&fragOff)
{
shortflags_host=ntohs(w);
fragOff=flags_host&0x1fff;
}
char*getProtocol(BYTEProtocol)
{
switch(Protocol)
{
case1:
return"ICMP";
case2:
return"IGMP";
case4:
return"IPinIP";
case6:
return"TCP";
case8:
return"EGP";
case17:
return"UDP";
case41:
return"IPv6";
case46:
return"RSVP";
case89:
return"OSPF";
default:
return"UNKNOW";
}
}
voidipparse(FILE*file,char*buffer)
{
IP_HEADERip=*(IP_HEADER*)buffer;//通过指针把缓冲区的内容强制转化为IP_HEADER数据结构
UDP_HEADERudp=*(UDP_HEADER*)buffer;
BYTEVersion,headerLen,DF,MF;
WORDfragOff;
getVersion(ip.Version,Version);
fprintf(file,"IP:
\r\n");
fprintf(file,"版本=%d\r\n",Version);
getIHL(ip.Headlen,headerLen);
fprintf(file,"报头长度=%d(BYTE)\r\n",headerLen);
fprintf(file,"优先级:
%s,服务类型:
%s\r\n",parseServiceType_getProcedence(ip.ServiceType),parseServiceType_getTOS(ip.ServiceType));
fprintf(file,"总长度=%d(BYTE)\r\n",ntohs(ip.TotalLen));
fprintf(file,"标识=%d\r\n",ntohs(ip.ID));
fprintf(file,"flags=%x\r\n",ip.Flags);
getFlags(ip.Flags,DF,MF);
fprintf(file,"标志DF=%d,MF=%d\r\n",DF,MF);
getFragOff(ip.FragOff,fragOff);
fprintf(file,"分片偏移=%d\r\n",fragOff);
fprintf(file,"TTL=%d(hopes)\r\n",ip.TTL);
fprintf(file,"协议类型=%s\r\n",getProtocol(ip.Protocol));
fprintf(file,"头部校验和=0x%0x\r\n",ntohs(ip.HdrChksum));
fprintf(file,"源IP地址=%s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));
fprintf(file,"目的IP地址=%s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));
fprintf(file,"\r\n");
if(ip.Protocol==17)
{fprintf(file,"UDP:
\r\n");
fprintf(file,"源端口:
%d\r\n",ntohs(udp.sourport));
fprintf(file,"目的端口:
%d\r\n",ntohs(udp.destport));
fprintf(file,"数据长度:
%d(BYTE)\r\n",ntohs(udp.uslength));
fprintf(file,"校验和:
0x%0x\r\n",ntohs(udp.checksum));
}
fprintf(file,"-------------------------------------------\r\n");
}
main()
{
charegg;
{
FILE*file;
if((file=fopen("ip.txt","wb+"))==NULL)
{
printf("failtoopenfile%s");
return-1;
}
WSADATAwsData;
if(WSAStartup(MAKEWORD(2,2),&wsData)!
=0)//第一个参数指明SOCKET版本,第二个返回请求的SOCKET版本信息
{
cout<<"WSAStartupfailed"<exit(0);
};
SOCKETsock;
sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
//第一个参数指定通信区域(INTERNET)
//第二个参数指明套接字类型(RAW_SOCKET)
//第三个参数指定套接字所用的特定协议(IP)
//第四个参数可置空(WSAPROTOCOL_INFO位)套接字初始化,用bind函数为套接字建立一个本地地址
//第六个参数设置发送接收的超时时间
charhostName[128];
gethostname(hostName,100);
hostent*pHostIP;
pHostIP=gethostbyname(hostName);
//填充SOCKADDR_IN结构
sockaddr_inaddr_in;
addr_in.sin_addr=*(in_addr*)pHostIP->h_addr_list[0];//IP地址输入到H端口
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(8000);
bind(sock,(sockaddr*)&addr_in,sizeof(addr_in));//第一个参数是已经创建的套接字
DWORDdwValue=1;//双字节//第二个参数由sockaddr_in结构被强制转换成sockaddr结构
//第三个参数是地址结构的长度
#defineIO_RCVALL_WSAIOW(IOC_VENDOR,1)
DWORDdwBufferLen[10];
DWORDdwBufferInLen=1;
DWORDdwBytesReturned=0;
WSAIoctl(sock,IO_RCVALL,&dwBufferInLen,sizeof(dwBufferInLen),&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);
#defineBUFFER_SIZE65535
charbuffer[BUFFER_SIZE];
//开始解析
cout<<"学生姓名:
刘国庆"<cout<<"学号:
1162310120"<cout<<"yourcomputernameis:
"<cout<<"youripaddressis:
"<<:
:
inet_ntoa(addr_in.sin_addr)<cout<<"doyouwanttocontinue?
Y/N:
"<cin>>egg;
intsize;
fprintf(file,"学生姓名:
刘国庆学号:
1162310120\r\n");
while(egg=='Y'||egg=='y')
{
intk;
cout<<"pleaseenterthenumber:
"<cin>>k;
while(k)
{
size=recv(sock,buffer,BUFFER_SIZE,0);
fprintf(file,"totallength%d\r\n",size);
fprintf(stdout,"totallength%d\r\n",size);
ipparse(stdout,buffer);
ipparse(file,buffer);
k--;
}
cout<<"doyouwanttocontinue?
Y/N:
"<cin>>egg;
}
fclose(file);
return0;
}
return0;
}