发送Ethernet+ARP数据包
- 格式:doc
- 大小:377.07 KB
- 文档页数:21
计算机网络基础课程设计报告题目:发送Ethernet AR P学生姓名:学号:专业班级:同组姓名:指导教师:设计时间: 2011年下学期第18周指导老师意见:评定成绩:签名:日期:2012年1 月5 日目录一、程设计的目的和意义 (2)二、设计的内容和要求 (2)2.1 基本要求 (2)2. 2系统开发语言及环境的选择 (3)三、设计的相关技术 (3)3.1 ARP协议及工作原理 (3)3.2工作原理: (4)四、程设计过程 (6)五、课程设计小结 (19)六、参考文献 (20)一、程设计的目的和意义IP地址将不同的物理地址统一起来,从而将物理地址隐藏起来,上层软件使用IP地址标识结点。
但是。
两台计算机只有在知道彼此的物理地址时才能进行通信。
IP数据包常通过Ethernet发送。
Ethernet设备并不识别32位IP地址,它们是以48位MAC地址传输Ethernet数据包的。
因此,IP驱动器必须把IP目的地址转换成Ethernet网络目的地址。
这两种地址之间存在着某种静态的或动态的映射,通常需要查看一张表来进行这种映射。
这种地址协议(ARP)就是用来确定这些映象的协议。
ARP工作时,送出一个所希望的IP地址的Ethernet广播数据包。
目的地主机以一个含有IP和Ethernet地址对的数据包作为应答。
发送者将这个地址对高速缓存起来,以节约不必要的ARP通信。
本课程设计的目的是进一步熟悉ARP协议的帧结构以及它的运行过程二、设计的内容和要求2.1 基本要求本次课程设计的基本要求是在熟悉ARP协议并了解Winpcap编程,或者下载JAVA类:jpcap包构造ARP包,选择并打开网卡,将ARP包发送。
1)命令行格式:arpsend src_ip src_mac dst_ip dst_mac flag其中arpsend作为程序名。
各参数意义:src_ip: 源IP地址。
src_mac: 源MAC地址。
dst_ip: 目的IP地址。
dst_mac: 目的MAC地址。
Flag:0表示ARP请求;1表示ARP应答。
例如:arpsend 192.168.1.1 FA:01:02:03:04:05 192.168.1.2 0D:E1:02:03:B4:06 12)输出:Send OK。
3)程序的正确性的检验。
可以安装一个截包软件,如Iris,运行该软件以查看能否收到程序发出的ARP包,并检查包中个字段填充的内容(如各地址,协议类型)是否正确。
错误!未指定书签。
2. 2系统开发语言及环境的选择操作系统:Windows XP Professional运行环境:Microsoft Visual C++ 6.0开发语言:C语言,C++等三、设计的相关技术3.1 ARP协议及工作原理ARP协议是“Address Resolution Protocol”(地址解析协议)的缩写。
在局域网中,网络中实际传输的是“帧”,帧里面是有目标主机的MAC地址的。
在以太网中,一个主机要和另一个主机进行直接通信,必须要知道目标主机的MAC 地址。
但这个目标MAC地址是如何获得的呢?它就是通过地址解析协议获得的。
所谓“地址解析”就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。
ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。
ARP的基本运行过程是:1)主机A希望发送数据分组给主机B,但不知道B的物理地址。
2)A发送广播报文,要求B主机用它的物理地址来响应。
3)网站上所有主机都接收到这个分组。
4)B识别出自己的IP地址,发送应答报文,告诉A自己的物理地址。
3.2 ARP的分组格式图一 ARP分组格式图2 物理帧头0 8 16 24 31(位)图3 ARP帧结构3.3工作原理:源主机在传输数据前,首先要对初始数据进行封装,在该过程中会把目的主机的IP地址和MAC地址封装进去。
在通信的最初阶段,我们能够知道目的主机的IP地址,而MAC地址却是未知的。
这时如果目的主机和源主机在同一个网段内,源主机会以第二层广播的方式发送ARP请求报文。
ARP请求报文中含有源主机的IP地址和MAC地址,以及目的主机的IP地址。
当该报文通过广播方式到达目的主机时,目的主机会响应该请求,并返回ARP响应报文,从而源主机可以获取目的主机的MAC地址,同样目的主机也能够获得源主机的MAC地址。
如果目的主机和源主机地址不在同一个网段内,源主机发出的IP数据包会送到交换机的默认网关,而默认网关的MAC地址同样可以通过ARP协议获取。
经过ARP协议解析IP地址之后,主机会在缓存中保存IP地址和MAC地址的映射条目,此后再进行数据交换时只要从缓存中读取映射条目即可。
ARP协议工作原理详见图4.图4 网段内ARP工作原理关于ARP的功能,仅限于在没有安全防护的网络里。
1) 如果有多个用户都在同一个网关上网,那么若要禁止机器A上网,应该怎么做呢?就是让A得不到正确的网关的ARP映射。
可以采取如下措施:伪装成网关,给机器A发送ARP包,该ARP的发送方为网关的IP,而MAC部分随便填一个地址;接收方正确填写A的相关信息。
2)基于ARP欺骗的监听。
如果某台计算机C和计算机A、B位于同一个局域网内,那么如何监听A和B间的通信呢?很简单,对A说“我是B”,在对B说“我是A”。
具体的操作如下:给A发送一个伪造的ARP回应包,告诉A,B的IP 对应的MAC为C的MAC地址,于是A就会相应地刷新自己的ARP缓存,将发给B 的数据都发送到主机C上来。
当然,因为ARP缓存是动态的,有超时时间,所以必须每隔一段时间就给A发送一个ARP回应包。
为了不让B发现,我们还要对每次接受到的数据包进行转发。
这样就监听了A发送给B的信息。
如果想监听B发送给A的信息,方法类似。
3.4 ARP包的填充将命令行的参数作适当的转换后填到ARP分组结构的各字段中即可。
要注意的是,填充请求包时。
因为包要在Ethernet上广播,所以,物理帧头的“目的MAC”字段要填充为FFFFFFFFFFFF;而ARP帧结构中的目的MAC可填充为任意值,因为它此时不起作用。
“填充数据”字段要填充为0。
四、程设计过程4.1 流程图图5 程序流程图4.2源程序#include <iostream.h>#include <fstream.h>#include <conio.h>#include <stdio.h>#include <stdlib.h>#include <Packet32.h>#include <Ntddndis.h>#pragma comment(lib,"ws2_32.lib")// DLC头typedef struct DLCHeader{unsigned char DesMAC[6];unsigned char SrcMAC[6];unsigned short Ethertype;} DLCHEADER;// ARP桢typedef struct ARPFrame{unsigned short HW_Type;unsigned short Prot_Type;unsigned char HW_Addr_Len;unsigned char Prot_Addr_Len;unsigned short Flag; unsigned char Send_HW_Addr[6];unsigned char Send_Prot_Addr[4]; unsigned char Targ_HW_Addr[6]; unsigned char Targ_Prot_Addr[4]; unsigned char padding[18];} ARPFRAME;// ARP包=DLC头+ARP桢typedef struct ARPPacket{DLCHeader dlcHeader;ARPFrame arpFrame;}*PARPPACKET;ARPPacket ARPPACKET;//源文件.cpp#include <iostream.h>#include <string.h>//#include "h.h"int transIP(char *,unsigned char *);int transMAC(char *,unsigned char *); LPADAPTER lpAdapter;LPPACKET lpPacket;bool Send();void main(int argc,char *argv[]){if(argc!=6){cout<<"输入格式错误"<<endl;return;}int i=0;memset(&ARPPACKET, 0, sizeof(ARPPACKET));if(*argv[5]=='0'){for(i=0;i<6;i++)ARPPACKET.dlcHeader.DesMAC[i]=0xff;ARPPACKET.arpFrame.Flag=(unsigned short)1;}else{if(*argv[5]=='1'){//填充DLC头中目的MAC地址if(!transMAC(argv[4],ARPPACKET.dlcHeader.DesMAC))return;//ARP桢中flag位置2ARPPACKET.arpFrame.Flag=(unsigned short)0x0200;}elsecout<<"flag位输入错误"<<endl;}if(!transMAC(argv[2],ARPPACKET.dlcHeader.SrcMAC))return;//填充DLC头中桢类型ARPPACKET.dlcHeader.Ethertype=htons((unsigned short)0x0608); ARPPACKET.arpFrame.HW_Type=(unsigned short)0x0100;//(Ethernet类型)ARPPACKET.arpFrame.Prot_Type=(unsigned short)0x0008;ARPPACKET.arpFrame.HW_Addr_Len=(unsigned char)6; ARPPACKET.arpFrame.Prot_Addr_Len=(unsigned char)4;if(!transMAC(argv[2],ARPPACKET.arpFrame.Send_HW_Addr)) return;if(!transIP(argv[1],ARPPACKET.arpFrame.Send_Prot_Addr)) return;if(!transMAC(argv[4],ARPPACKET.arpFrame.Targ_HW_Addr)) return;if(!transIP(argv[3],ARPPACKET.arpFrame.Targ_Prot_Addr)) return;for(i=0;i<18;i++)ARPPACKET.arpFrame.padding[i]=0;if(!Send())cout<<"发送arp包失败"<<endl;}int transIP(char *argv,unsigned char *a){char ip[16];int i=0,j=0,k=0;strcpy(ip,argv);int m=strlen(argv);for(i=0;i<m;i++) //判断命令行输入的IP格式是否正确 {if((ip[i]<'0'||ip[i]>'9')&&ip[i]!='.'){cout<<"输入ip:"<<argv<<"格式错误"<<endl;return 0;}else{if(ip[i]!='.')j++;else{k++;if(j>3){cout<<"输入ip:"<<argv<<"格式错误"<<endl; return 0;}else{j=0;}if(k>3){cout<<"输入ip:"<<argv<<"格式错误"<<endl; return 0;}}}}j=0;for(i=0;i<4;i++) //填充IP地址 {while(*(ip+j)<'0'||*(ip+j)>'9')j++;a[i]=(unsigned char)atoi(ip+j);while(*(ip+j)>='0'&&*(ip+j)<='9')j++;}return 1;}int transMAC(char *argv,unsigned char *b){char mac[18];int i=0,j=0,k=0;strcpy(mac,argv);int m=strlen(argv);for(i=0;i<m;i++) //判断命令行输入的MAC地址是否正确{if(mac[i]<'0'||(mac[i]>':'&&mac[i]<'A')||(mac[i]>'Z'&&mac[i]<'a')||mac[i]>'Z') {cout<<"输入mac:"<<argv<<"格式错误"<<endl;return 0;}else{if(mac[i]!=':')j++;else{k++;if(j>2){cout<<"输入mac"<<argv<<"格式错误"<<endl;return 0;}else{j=0;}if(k>5){cout<<"输入mac"<<argv<<"格式错误"<<endl;return 0;}}}}for(i=0;i<6;i++) //填充MAC地址{while(*(mac+j)==':'||*(mac+j)=='-')j++;if(*(mac+j)>='0'&&*(mac+j)<='9')b[i]=(unsigned char)(*(mac+j)-'0');if(*(mac+j)>='a'&&*(mac+j)<='z')b[i]=(unsigned char)(*(mac+j)-'a'+10); if(*(mac+j)>='A'&&*(mac+j)<='z')b[i]=(unsigned char)(*(mac+j)-'A'+10); j++;b[i]*=16;if(*(mac+j)>='0'&&*(mac+j)<='9')b[i]+=(unsigned char)(*(mac+j)-'0');if(*(mac+j)>='a'&&*(mac+j)<='z')b[i]+=(unsigned char)(*(mac+j)-'a'+10); if(*(mac+j)>='A'&&*(mac+j)<='z')b[i]+=(unsigned char)(*(mac+j)-'A'+10); j++;}return 1;}bool Send(){char AdapterNameA[8192];char AdapterNameU[2*sizeof(AdapterNameA)];unsigned long AdapterAlength=sizeof(AdapterNameA);unsigned long AdapterUlength=2*sizeof(AdapterNameA);DWORD dwVersion=GetVersion ();DWORD dwWindowsMajorVersion=(DWORD)(LOBYTE(LOWORD(dwVersion)));if(!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >=4)){//Windows NT//获取UNICODE码网卡名列表if(PacketGetAdapterNames(AdapterNameU,&AdapterUlength)==FALSE) {cout<<"无法得到网卡列表!"<<endl;return FALSE;}//将第一个网卡名转为ASCII码unsigned short *pAdapterName=(unsigned short *)AdapterNameU; for(unsigned i=0;i<AdapterAlength;i++)if((AdapterNameA[i]=(char)pAdapterName[i])=='\0')break;}else{//Windows 9x//获取ASCII码网卡名列表if(PacketGetAdapterNames(AdapterNameA,&AdapterAlength)==FALSE)cout<<"无法得到网卡列表!"<<endl;return FALSE;}}lpAdapter=PacketOpenAdapter(AdapterNameA);if(!lpAdapter||lpAdapter->hFile==INVALID_HANDLE_VALUE){cout<<"无法打开网卡,错误码:"<<GetLastError()<<endl;return FALSE;}//发送帧LPPACKET lpPacket; //分配发送包结构if((lpPacket=PacketAllocatePacket())!=NULL){//初始化发送包结构PacketInitPacket(lpPacket,&ARPPACKET,sizeof(ARPPACKET)); // 每次只发送一个包PacketSetNumWrites(lpAdapter,1);//发送包if(PacketSendPacket(lpAdapter,lpPacket,true)==1){cout<<"send ok"<<endl;}else{cout<<"发送包失败"<<endl;PacketFreePacket(lpPacket); //释放发送包结构}else{cout<<"分配发送包LPPACKET结构失败!"<<endl;}PacketCloseAdapter(lpAdapter);return TRUE;}4.3运行结果1.应该在预编译代码区加上预编译指令:#pragma comment(lib, "ws2_32.lib");否则,链接时会出现符号无法解析的错误。