计算机网络课设报告解析ARP数据包含C++源码

  • 格式:doc
  • 大小:94.00 KB
  • 文档页数:11

课程设计任务书目录1.课程设计目的 (2)2.课程设计要求 (2)3.相关知识 (2)1)ARP数据报的消息格式 (3)2)ARP协议的工作流程 (4)4.课程设计分析 (5)1)课程设计中的重点及难点 (5)2)参考算法 (6)3)核心代码 (7)5.相关扩展 (8)6.心得体会 (10)7.参考文献 (11)一、课程设计目的:本课程设计的目的是对网络上的ARP数据包进行解析,从而熟悉ARP数据包的结构,对ARP协议有更好的理解和认识。

二、课程设计要求:通过编制程序,获取网络中的ARP数据包,解析数据包的内容,将结果显示在标准输出上,并同时写入日志文件。

程序的具体要求如下所示:1,以命令行的形式运行,如下所示:arpparse logfile其中,arpparse为程序名;logfile为日志文件名。

2,程序输出内容如下所示:源IP地址源MAC地址目的IP地址操作时间各部分的说明如下所示:源IP地址:输出ARP消息格式中的源IP地址字段源MAC地址:输出ARP消息格式中的源物理地址字段目的IP地址:输出ARP消息格式中的目的IP地址字段。

目的MAC地址:输出ARP消息格式中的目的物理地址字段操作:输出ARP消息格式中的操作字段,若为ARP请求,则为1,若为ARP应答,则为2,时间:该ARP包产生的时间3,当程序接收到键盘输入Ctrl+C时字段三、相关知识a)ARP数据报的消息格式网络上的每台主机或设备都有一个或多个IP地址。

IP地址是网络层的地址,在网络层,数据被组装成IP包。

但是发送IP包需要物理设备的支持(通常是Ethernet设备,在本课程设计中我们指定为Ethernet设备),即发送端必须知道目的物理地址才能将IP包发送出去,所以需要一种将IP地址映射为物理地址的机制。

ARP协议就是用来完成这个任务的。

ARP协议能够在同一个物理网络中,在给定目的主机或设备的IP地址的条件下,得到目的主机或设备的物理地址。

ARP协议的数据包格式如图所示:ARP数据包的消息格式下面对数据包的各个部分进行说明●硬件类型:指定硬件接口类型。

例如,值为1表示Ethernet●协议类型:指定发送方支持的上层协议的类型●物理地址长度:指定物理(硬件)地址的长度●协议地址长度:网络层协议的地址长度。

若为IP协议,其值为4●操作:指定ARP的操作类型,例如,1表示ARP请求,2表示ARP应答●源物理地址:指定发送方的IP地址●目的物理地址:指定目的物理地址。

●目的IP地址:指定目的IP地址ARP分组必须在数据链路层中被封装成侦,才能发送出去封装形式如图所示b)ARP协议的工作流程。

1)在发送一个ARP分组之前,源主机首先根据目的IP地址,在本地ARP高速缓存表中查找与之对应的目的物理地址。

如果找到对应的物理地址,就不用进行地址解析,否则需要进行地址解析。

2)实现地址解析的第一步是产生ARP请求分组。

在相应的字段写入本地主机的源物理地址、源IP地址,在目的物理地址字段写入0,并在操作字段写入1。

3)将ARP分组发送到本地的数据链路层,并封装成帧。

以源物理地址作为源地址,以物理广播地址(FF-FF-FF-FF-FF-FF)作为目的地址,通过物理层发送出去。

4)由于采用了广播地址,因此网段内所有的主机或设备都能接受到该帧。

除了目的主机外,所有接受到该分组的主机和设备都会丢弃该分组,因为目的主机能够识别ARP 消息中的目的IP地址。

5)目的主机发送ARP应答分组。

在ARP应答分组中,以请求分组中源物理地址、源IP地址作为其目的物理地址、目的IP地址,并将目的主机自身的物理地址、IP地址填入应答分组的源物理地址、源IP地址字段,并在操作字段中写入2。

该分组通过数据链路层以点对点的方式发送出去(因为现在目的方已经知道双方的物理地址)。

6)源结点接收到ARP应答分组,知道对应于目的IP地址的目的物理地址,将它作为一条新记录加入到ARP高速缓存表。

7)源结点将有完整源IP地址、源物理地址、目的IP地址、目的物理地址的信息和数据作为一个发送分组,传送给它的数据链路层并封装成桢,然后以点对点的方式发送到目的主机。

四、课程设计分析1.课程设计中的重点及难点1)程序中会用到Winpcap,Winpcap是Win32环境下数据包捕获的开放代码函数库。

基于Winpcap的应用程序一般按照下面几个步骤进行设计:●输出网卡设备列表。

●选择网卡并打开。

●捕获数据包时,可能需要设置过滤器。

●捕获数据包或者发送数据包。

2)在程序设计过程中需要注意网络—主机字节顺序的转化。

由于不同的计算机系统所采用的数据表示方式不同,对于2B或4B的数据,有的采用低字节地址存放数据的高权值位,而有的却以低地址字节存放数据低权位值,在网络的数据传输中,我们应该统一表示,所以我们在捕获数据包后,应将数据包头部的表示长度或类型的数据转换成本地机的表达形式。

可以利用函数ntohs()将网络字节序转换为主机字节序。

3)选择网卡并打开时,注意选择可用的网卡。

2.参考算法1)取得当前网卡设备列表。

2)选择Ethernet网卡并打开,注意判断所选网卡是否为实际存在的可用网卡。

3)设置过滤器,此处的过滤器正则表达式为“arp”或者“ether proto\\arp”。

4)捕获数据包并进行处理(包括输出各IP地址,物理地址,操作类型以及时间)。

由于要记录日志文件,为了便于输出流参数,建议采用pcap_next_ex()函数。

流程图如图所示:3.核心代码●ARP数据包结构struct arppkt{unsigned short hdtyp; //硬件类型。

值0001表示其为Ethernetunsigned short protyp; //协议类型。

值0800表示上层协议为IPunsigned char hdsize; //硬件地址长度。

值为06unsigned char prosize; //协议地址长度。

值为04unsigned short op; //操作值为0001/0002,分别表示ARP请求/应答u_char smac[6]; //源MAC地址,6Bu_char sip[4]; //源IP地址,4Bu_char dmac[6]; //目的MAC地址u_char dip[4]; //目的IP地址};●获取网络设备列表,并以混杂模式打开网络设备//获取网络设备列表if(pcap_findalldevs(&alldevs,errbuf)==-1){cout<<"Error in pcap_findalldevs:"<<errbuf;return;}//选择Ethernet卡for(d=alldevs;d;d=d->next){//以混杂模式打开网卡,以接受所有的帧if((adhandle=pcap_open_live(d->name,1000,1,300,errbuf))==NULL){cout<<"\nUnable to open the adapter.";pcap_freealldevs(alldevs); //释放设备列表return;}if(pcap_datalink(adhandle)==DLT_EN10MB&&d->addresses!=NULL)break;}●编译过滤器并设置过滤器,只捕获ARP数据包char packet_filter[]=”ether proto \\arp”; //过滤,选择arp协议if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0){ cout<<"\nUnable to compile the packet filter.Check the syntax.\n";pcap_freealldevs(alldevs);return;}//设置过滤器if(pcap_setfilter(adhandle,&fcode)<0){ cout<<"\nError setting the filter.\n";pcap_freealldevs(alldevs);return;}●循环捕获ARP包,并进行解析while((result=pcap_next_ex(adhandle,&header,&pkt_data))>=0){输出ARP数据包的各个域的内容到文件和屏幕上}●源程序#include<winsock2.h>#pragma comment(lib,"Ws2_32.lib") //用到ntobs()//等同于点击"project-setting-link"打开object/library module编辑框后加入文件#pragma comment(lib,"wpcap.lib")#include "pcap.h" //此头文件没有包含在VC中,需要另外加入#include<fstream.h>#include<iomanip.h> //格式化输出需要用到#include<conio.h> //用到_getch()//注意到接收的数据包头中代表类型,数据长度的字段采用的是big-endian//所以对于2B/4B的数据要用ntohs()转换为本机形式//ARP包结构struct arppkt{unsigned short hdtyp; //硬件类型.值0001unsigned short protyp;unsigned char hdsize;unsigned char prosize;unsigned short op;u_char smac[6];u_char sip[4];u_char dmac[6];u_char dip[4];};void packet_handler(const pcap_pkthdr *header,const u_char *pkt_data,ostream& out); void main(int argc,char *argv[ ]){if(argc!=2){cout<<"Usage:arpparse logfilename"<<endl;cout<<"press any key to continue."<<endl;_getch();return;}pcap_if_t *alldevs;pcap_if_t *d;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[]="ether proto \\arp";struct bpf_program fcode;struct pcap_pkthdr *header;const u_char *pkt_data;if(pcap_findalldevs(&alldevs,errbuf)==-1){cout<<"Error in pcap_findalldevs:"<<errbuf;return;}for(d=alldevs;d;d=d->next){if((adhandle=pcap_open_live(d->name,1000,1,300,errbuf))==NULL){cout<<"\nUnable to open the adapter.";pcap_freealldevs(alldevs);return;}if(pcap_datalink(adhandle)==DLT_EN10MB&&d->addressess!=NULL) break;}if(d==NULL){cout<<"\nNo interfaces found! Make sure Winpcap is installed.\n";return;}//获得子网掩码netmask=((sockaddr_in *)(d->netmask))->sin_addr.s_un.s_addr;//编译过滤器,只捕获ARP包if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0){ cout<<"\nUnable to compile the packet filter.Check the syntax.\n"; pcap_freealldevs(alldevs);return;}//设置过滤器if(pcap_setfilter(ashandle,&fcode)<0){ cout<<"\nError setting the filter.\n";pcap_freealldevs(alldevs);return;}cout<<"\t\tlistening on "<<d->description<<"..."<<endl<<endl;//显示提示信息及每项含义ofstream fout(argv[1],ios::app); //日志记录文件//为了查看日志时的方便,其中加入了日期记录time_t t;time(&t);fout.seekp(0,ios::end);if(fout.tellp()!=0)fout<<endl;fout<<"\t\tARP request(1)/reply(2) on"<<ctime(&t);cout<<Sour Ip Addr"<<" "<<"Sour MAC Address"<<" "<<"Des Ip Addr"<<" "<<"Des MAC Address"<<" "<<"OP"<<" "<<"Time"<<endl;fout<<Sour Ip Addr"<<" "<<"Sour MAC Address"<<" "<<"Des Ip Addr"<<" "<<"Des MAC Address"<<" "<<"OP"<<" "<<"Time"<<endl;//释放设备列表pcap_freealldevs(alldevs);int result;while((result=pcap_next_ex(adhandle,&header,&pkt_data))>=0){if(result==0)continue;packer_handler(header,pkt_data,cout);packet_handler(header,pkt_data,fout);}}void packet_handler(const pcap_pkthdr *header,const u_char *pkt_data,ostream& out){arpkt* arph = (arppkt *)(pkt_data +14);for(int i=0;i<3;i++)out<<int(arph->sip[i])<<'.';out.setf(ios::left);out<<setw(3)<<int(arph->sip[3])<<" ";out.unsetf(ios::uppercase);for(i=0;i<5;i++)out<<hex<<setw(2)<<int(arph->smac[i])<<'-';out<<hex<<setw(2)<<int(arph->smac[5])<<" ";out.fill(oldfillchar);out.unsetf(ios::hex|ios::uppercase);for(i=0;i<3;i++)out<<int(arph->dip[3])<<'.';out.unsetf(ios::left);//输出目的MAC地址out.fill('0');out.setf(ios::uppercase);for(i=0;i<5;i++)out<<hex<<setw(2)<<int(arph->dmac[i])<<'-';out.fill(oldfillchar);out.unsetf(ios::hex|ios::uppercase);out<<ntohs(arph->op)<<" ";struct tm *ltime;ltime=localtime(&header->_sec);out.fill('0');out<<ltime->tm_hour<<':'<<setw(2)<<ltime->tm_min<<':'<<setw(2)<<ltime->tm_sec;out.fill(oldfillchar);out<<endl;}五、相关扩展本课程设计还可以在Linux环境下用rawsocket完成。