地址解析协议(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欺骗可以导致目标计算机与网关通信失败;
请见代码
[cpp] view plaincopy
- #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;
- }
- }
- }
-
- }
|