地址解析协议(Address Resolution Protocol,ARP)是在仅知道主机的IP地址时确 地址解析协议定其物理地址的一种协议。因IPv4和以太网的广泛应用,其主要用作将IP地址翻译为以太网的MAC地址,但其也能在ATM( 异步传输模式)和FDDIIP(Fiber Distributed Data Interface 光纤分布式数据接口)网络中使用。从IP地址到物理地址的映射有两种方式:表格方式和非表格方式。ARP具体说来就是将网络层(IP层,也就是相当于OSI的第三层)地址解析为数据连接层(MAC层,也就是相当于OSI的第二层)的MAC地址。
1. 什么是ARP?
ARP (Address Resolution Protocol) 是个地址解析协议。最直白的说法是:在IP-以太网中,当一个上层协议要发包时,有了节点的IP地址,ARP就能提供该节点的MAC地址。
2. 为什么要有ARP?
OSI 模式把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface). IP地址在第三层, MAC地址在第二层。协议在发送数据包时,得先封装第三层(IP地址),第二层(MAC地址)的报头, 但协议只知道目的节点的IP地址,不知道其MAC地址,又不能跨第二、三层,所以得用ARP的服务。
3. 什么是ARP
cache? ARP cache 是个用来储存(IP, MAC)地址的缓冲区。当ARP被询问一个已知IP地址节点的MAC地址时,先在ARP cache 查看,若存在,就直接返回MAC地址,若不存在,才发送ARP request向局域网查询。
4. ARP 有什么命令行?
常用的包括:(格式因操作系统、路由器而异,但作用类似)- 显示ARP cache: show arp; arp -a - 清除ARP cache: arp -d;clear arp。
在TCP/IP协议中,A给B发送IP包,在报头中需要填写B的IP为目标地址,但这个IP包在以太网上传输的时候,还需要进行一次以太包的封装,在这个以太包中,目标地址就是B的MAC地址.
计算机A是如何得知B的MAC地址的呢?解决问题的关键就在于ARP协议。
在A不知道B的MAC地址的情况下,A就广播一个ARP请求包,请求包中填有B的IP(192.168.1.2),以太网中的所有计算机都会接收这个请求,而正常的情况下只有B会给出ARP应答包,包中就填充上了B的MAC地址,并回复给A。
A得到ARP应答后,将B的MAC地址放入本机缓存,便于下次使用。
本机MAC缓存是有生存期的,生存期结束后,将再次重复上面的过程。
ARP协议并不只在发送了ARP请求才接收ARP应答。当计算机接收到ARP应答数据包的时候,就会对本地的ARP缓存进行更新,将应答中的IP和MAC地址存储在ARP缓存中。因此,当局域网中的某台机器B向A发送一个自己伪造的ARP应答,而如果这个应答是B冒充C伪造来的,即IP地址为C的IP,而MAC地址是伪造的,则当A接收到B伪造的ARP应答后,就会更新本地的ARP缓存,这样在A看来C的IP地址没有变,而它的MAC地址已经不是原来那个了。由于局域网的网络流通不是根据IP地址进行,而是按照MAC地址进行传输。所以,那个伪造出来的MAC地址在A上被改变成一个不存在的MAC地址,这样就会造成网络不通,导致A不能Ping通C!这就是一个简单的ARP欺骗。
在网络执法官中,要想限制某台机器上网,只要点击“网卡”菜单中的“权限”,选择指定的网卡号或在用户列表中点击该网卡所在行,从右键菜单中选择“权限”,在弹出的对话框中即可限制该用户的权限。对于未登记网卡,可以这样限定其上线:只要设定好所有已知用户(登记)后,将网卡的默认权限改为禁止上线即可阻止所有未知的网卡上线。使用这两个功能就可限制用户上网。其原理是通过ARP欺骗发给被攻击的电脑一个假的网关IP地址对应的MAC,使其找不到网关真正的MAC地址,这样就可以禁止其上网。
ARP欺骗可以导致目标计算机与网关通信失败;
请见代码
#include "stdafx.h" #include <iostream> #include <fstream> #include <pcap.h> #include <remote-ext.h> #include "CheckSum.h" #include "Aho-Corasick.h" using namespace std; #pragma comment(lib,"wpcap.lib") #pragma comment(lib,"ws2_32.lib") bool cut = false; pcap_t * adapter; //检查数据包,进行模式匹配,并阻断非法连接 void CheckPacket(const u_char *pkt_data); //winpcap中pcap_loop()函数的回调函数--当网卡捕获到指定数据包时调用 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); //保存缓存数据到文件 bool SaveToFile(char filename[], const void *data,const unsigned int size); //保存网页数据到文件 void SavePacket(const u_char *pkt_data); //构造发向服务器的RST包 void RSTPacketToServer(const u_char *old_pkt,u_char *pkt); //构造发向客户端的RST包 void RSTPacketToClient(const u_char *old_pkt,u_char *pkt); int _tmain(int argc, _TCHAR* argv[]) { prec(); pcap_if_t *alldevs; pcap_if_t *d; char errbuf[PCAP_ERRBUF_SIZE]; int num_adapter=0; unsigned int netmask; char packet_filter[] = "tcp port 80"; struct bpf_program fcode; /* Retrieve the device list from the local machine */ if(pcap_findalldevs(&alldevs,errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); exit(1); } /* Print the list */ for(d= alldevs; d != NULL; d= d->next) { printf("%d. %s\n", ++num_adapter, d->name); pcap_addr *addrs = d->addresses; while(addrs != NULL) { sockaddr_in *addr = (sockaddr_in *)addrs->addr; char *address = inet_ntoa(addr->sin_addr); printf("%s\n",address); addrs = addrs->next; } if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if (num_adapter == 0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); pcap_freealldevs(alldevs); return -1; } cout<<"Enter the adapter's number!\n"; int num = 0; cin >> num; if(num > num_adapter || num < 1) { cout<<"\nInterface number out of range.\n"; pcap_freealldevs(alldevs); return -1; } d = alldevs; for(int i = 0;i < num - 1;i++) { d = d->next; } // 打开选择的网络接口 adapter = pcap_open_live(d->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1,errbuf); if(adapter==NULL) { cout <<"\nUnable to open the adapter. "<<d->name<<" is not supported by WinPcap\n"; pcap_freealldevs(alldevs); return -1; } /* Check the link layer. We support only Ethernet for simplicity */ if (pcap_datalink(adapter) != DLT_EN10MB) { cout<<"is program works only on Ethernet networks.\n"; /* Free the devices list */ pcap_freealldevs(alldevs); return -1; } if (d->addresses != NULL) /* Retrieve the mask of the first address of the interface */ netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; else /* If the interface is without an address we suppose to be in a C class network */ netmask=0xffffff; //compile the filter if (pcap_compile(adapter, &fcode, packet_filter, 1, netmask) < 0) { cout<<"\nUnable to compile the packet filter. Check the syntax.\n"; /* Free the device list */ pcap_freealldevs(alldevs); return -1; } //set the filter if (pcap_setfilter(adapter, &fcode) < 0) { cout<<"\nError setting the filter.\n"; /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* We don't need any more the device list. Free it */ pcap_freealldevs(alldevs); cout <<"Listening....."<<endl; if(pcap_loop(adapter,0,packet_handler,NULL) == -2) { cout<<"\nTotal:\n"; pcap_stat * state = new pcap_stat(); pcap_stats(adapter,state); cout <<"ps_drop:"<< state->ps_drop<<"\n"; cout <<"ps_ifdrop:"<< state->ps_ifdrop<<"\n"; cout <<"ps_recv:"<< state->ps_recv<<"\n"; } else { cout << "something wrong when caputer the network's packet!\n"; return -1; } pcap_close(adapter); system("pause"); return 0; } void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { //保存数据包到文件 SavePacket(pkt_data); CheckPacket(pkt_data); } void SavePacket(const u_char *pkt_data) { //获得以太网头 ip数据包头 tcp头位置 Ip_Header* ipHeader; Tcp_Header* tcpHeader; unsigned int ipHeaderLen; unsigned short sport, dport; //Ethernet frame Ether_Header* eh = (Ether_Header*)pkt_data; //retrieve the position of the ip header ipHeader = (Ip_Header*)(pkt_data + 14); //length of ethernet header //retrieve the position of the tcp header ipHeaderLen = (ipHeader->iphVerLen & 0xf) * 4; //length of ip header tcpHeader = (Tcp_Header*)(pkt_data + 14 + ipHeaderLen); // 将端口信息从网络型转变为主机顺序 sport = ntohs(tcpHeader->sourcePort); dport = ntohs(tcpHeader->destinationPort); UCHAR Flags = tcpHeader->flags; //得到Tcp数据部分的位置 unsigned int TcpHeadLen = ((tcpHeader->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移 unsigned char* HttpData = (unsigned char*)tcpHeader+TcpHeadLen; unsigned int IpLength = ntohs(ipHeader->ipLength); unsigned int HttpDataLen = IpLength - ipHeaderLen - TcpHeadLen; if(HttpDataLen != 0) { //保存 SaveToFile("cap.log",HttpData,HttpDataLen); } } // // 把数据写入文件 // 入口参数: filename ==> 数据文件名 data ==> 指向数据块的空指针 size ==> 数据块大小 // 返回值类型 bool // bool SaveToFile(char filename[], const void *data,const unsigned int size) { ofstream onput; onput.open(filename,ios::out|ios.binary|ios::ate|ios::app); if(onput.fail()) return false; onput.write((char *)data,size); onput.close(); return true; } //构造R发送给服务器端的RST包 //输入:old_pkt - 收到的原数据包 pkt - 构造出来的RST包 void RSTPacketToServer(const u_char *old_pkt,u_char *pkt) { Ip_Header *old_ih,*ih; Tcp_Header *old_th,*th; Ether_Header *old_eh,*eh; unsigned int ipHeaderLen; memcpy (pkt,old_pkt,40+14); old_eh = (Ether_Header *)old_pkt; eh = (Ether_Header *)pkt; memcpy(old_eh->dhost,eh->shost,sizeof(eh->shost)); memcpy(old_eh->shost,eh->dhost,sizeof(eh->dhost)); /* retrieve the position of the ip header */ old_ih = (Ip_Header*)(old_pkt + 14); /* length of ethernet header */ ih = (Ip_Header*)(pkt + 14); memcpy(ih,old_ih,sizeof(Ip_Header)); //ip头 ih->ipSource = old_ih->ipDestination; ih->ipDestination = old_ih->ipSource; ih->ipLength = htons(40); /* retrieve the position of the udp header */ ipHeaderLen = (old_ih->iphVerLen & 0xf) * 4; old_th = (Tcp_Header*)(old_pkt + 14 + ipHeaderLen); th = (Tcp_Header*)(pkt + 14 + ipHeaderLen); th->destinationPort = old_th->sourcePort; th->sourcePort = old_th->destinationPort; th->flags = 0x04; //rst th->sequenceNumber = htonl(ntohl(old_th->acknowledgeNumber)); unsigned int TcpHeadLen = ((th->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移 unsigned char* HttpData = (unsigned char*)th+TcpHeadLen; int lentcp = ntohs(ih->ipLength) - (sizeof(Ip_Header) + sizeof(Tcp_Header)); th->acknowledgeNumber=0; ih->ipChecksum = 0; th->checksum = 0; ih->ipChecksum = checksum((USHORT *)ih, sizeof(Ip_Header)); ComputeTcpPseudoHeaderChecksum(ih, th, (char *)HttpData, lentcp); } //构造R发送给客户端的RST包 //输入:old_pkt - 收到的原数据包 pkt - 构造出来的RST包 void RSTPacketToClient(const u_char *old_pkt,u_char *pkt) { Ip_Header *old_ih,*ih; Tcp_Header *old_th,*th; Ether_Header *old_eh,*eh; unsigned int ipHeaderLen; memcpy (pkt,old_pkt,40+14); old_eh = (Ether_Header *)old_pkt; eh = (Ether_Header *)pkt; /* retrieve the position of the ip header */ old_ih = (Ip_Header*)(old_pkt + 14); /* length of ethernet header */ ih = (Ip_Header*)(pkt + 14); memcpy(ih,old_ih,sizeof(Ip_Header)); //ip头 ih->ipLength = htons(40); /* retrieve the position of the udp header */ ipHeaderLen = (old_ih->iphVerLen & 0xf) * 4; old_th = (Tcp_Header*)(old_pkt + 14 + ipHeaderLen); th = (Tcp_Header*)(pkt + 14 + ipHeaderLen); th->flags =4; //rst unsigned int TcpHeadLen = ((th->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移 unsigned char* HttpData = (unsigned char*)th+TcpHeadLen; int lentcp = ntohs(ih->ipLength) - (sizeof(Ip_Header) + sizeof(Tcp_Header)); th->sequenceNumber = htonl(ntohl(old_th->sequenceNumber) + lentcp); if(old_th->flags & 0x02) th->sequenceNumber = htonl(ntohl(old_th->sequenceNumber) + 1); th->acknowledgeNumber = 0; ih->ipChecksum = 0; th->checksum = 0; ih->ipChecksum = checksum((USHORT *)ih, sizeof(Ip_Header)); ComputeTcpPseudoHeaderChecksum(ih, th, (char *)HttpData, lentcp); } void CheckPacket(const u_char *pkt_data) { //获得以太网头 ip数据包头 tcp头位置 Ip_Header* ipHeader; Tcp_Header* tcpHeader; unsigned int ipHeaderLen; //Ethernet frame Ether_Header* eh = (Ether_Header*)pkt_data; //retrieve the position of the ip header ipHeader = (Ip_Header*)(pkt_data + 14); //length of ethernet header //retrieve the position of the tcp header ipHeaderLen = (ipHeader->iphVerLen & 0xf) * 4; //length of ip header tcpHeader = (Tcp_Header*)(pkt_data + 14 + ipHeaderLen); //得到Tcp数据部分的位置 unsigned int TcpHeadLen = ((tcpHeader->headerLen_unUsed & 0xf0) >> 4) * 4; // 高4位表示数据偏移 unsigned char* HttpData = (unsigned char*)tcpHeader+TcpHeadLen; unsigned int IpLength = ntohs(ipHeader->ipLength); int HttpDataLen = (int)(IpLength - ipHeaderLen - TcpHeadLen); if(cut) { if(tcpHeader->flags & 0x02) { u_char * send_mdata = new u_char[54]; RSTPacketToServer(pkt_data,send_mdata); pcap_sendpacket(adapter,send_mdata,54); return; } } if(HttpDataLen > 0) { for (int i = 0 ; i < HttpDataLen; i++) { if (AC(*(HttpData+i),false)) //ac算法 { printf("---------------------------------------------------\n"); printf("关键字位置:%d\n",i); cut = true; // u_char * send_data = new u_char[54]; //发送rst包给客户端 RSTPacketToClient(pkt_data,send_data); pcap_sendpacket(adapter,send_data,54); //发送rst包给服务端 RSTPacketToServer(pkt_data,send_data); pcap_sendpacket(adapter,send_data,54); cout<<"Finded!"<<endl; } } } }