#include "iostream.h"
#pragma comment(lib,"ws2_32.lib")
#define HAVE_REMOTE
#include "pcap.h"
#include "windows.h"
#include<fstream.h>
//******************************************************************************************************************
//*****************************************全局变量声明*************************************************************
//******************************************************************************************************************
CRITICAL_SECTION cs;//临界区定义
int myThreadCount = 0;//线程数目
pcap_if_t *d;//全局变量,存放选中的网络设备
pcap_pkthdr* pktHd;//存放收到包的包头
const unsigned char* pktDt;//存放收到包的数据域
pcap_t *pt;//全局变量,存放打开的网络连接句柄
unsigned int iptosendn,iptosendh,localip,nlNetMask,HostNum;//iptosendn要发送的网络序的目的IP地址,iptosendh要发的主机序的IP地址
unsigned char localmac[6]={0,0,0,0,0,0}; //存放本机MAC地址
#pragma pack(1)//操作系统界地址对齐方式换为网络对齐方式
struct ethernet_head//以太网物理帧头
{unsigned char dest_mac[6];
unsigned char source_mac[6];
unsigned short eh_type;
};
struct arp_head//ARP数据包数据部分结构
{unsigned short hardware_type; // 2硬件类型:Ethernet网接口类型为1
unsigned short protocol_type; // 2协议类型:IP协议类型为0x0800
unsigned char add_len; // 1硬件地址长度:MAC地址长度为6字节
unsigned char pro_len; // 1协议地址长度:IP地址长度为4字节
unsigned short option; // 2ARP操作类型:1表示请求,2表示应答
unsigned char sour_addr[6]; // 6源MAC地址:发送方的MAC地址
unsigned long sour_ip; // 4源IP地址:发送方的IP地址
unsigned char dest_addr[6]; // 6目的MAC地址:在ARP请求中没有意义,在ARP响应中为接收方的MAC地址
unsigned long dest_ip; // 4目的IP地址:在ARP请求中为待解析的IP地址,在ARP响应中为接收方的IP地址
unsigned char padding[18]; // 18填充字节:用来补齐最小长度
};
struct arp_packet//ARP数据包结构
{ ethernet_head eth;
arp_head arp;
}myPacket;//全局变量,存放ARP请求数据包
#pragma pack()//界地址对齐方式回到操作系统方式
//******************************************************************************************************************
//*****************************************全局函数声明*************************************************************
//******************************************************************************************************************
void MakePacket(int sourceip,int destip,arp_packet *parp_packet);//封包函数声明
DWORD WINAPI threadofrcv(LPVOID);//接收线程声明
DWORD WINAPI threadofsnt(LPVOID);//发送线程声明
//******************************************************************************************************************
//*****************************************程序主函数***************************************************************
//******************************************************************************************************************
main()
{
cout<<"**********************************************************************"<<endl;
cout<<"**********************************************************************"<<endl;
cout<<"*****************ARP协议获取局域网活动主机MAC地址程序*****************"<<endl;
cout<<"**********************************************************************"<<endl;
cout<<endl;
//***********************************下面取得本机网络设备************************************************
cout<<"******************************设备列表如下****************************"<<endl;
InitializeCriticalSection(&cs);//初始化临界区资源
pcap_if_t *alldevs;
pcap_addr *pAdr;
int inum;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
char packet_filter[] = "ip and udp";
short usability[255]; //usability用来保存某个设备的可用性
memset(usability,1,255);//初值假设全部可用
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)//获得设备列表
{
cout<<"搜索设备时出错!"<<endl;
exit(1);
}
for(d=alldevs; d; d=d->next)//打印本机可用的所有网络设备
{
cout<<"网卡序号 ["<<++i<<"]:"<<endl;
cout<<"网卡名称:"<<d->name<<endl;
if (d->description)
cout<<"描述信息:"<<d->description<<endl;
else
cout<<"描述信息:"<<"无!"<<endl;
if(d->addresses!=NULL)
{
cout<<"可用性 :可用!"<<endl;
usability[i]=1;
}
else
{
cout<<"可用性 :不可用!"<<endl;
usability[i]=0;
}
cout<<endl;
}
if(i==0)
{
cout<<"没有找到可用网卡!"<<endl;
return -1;
}
cout<<"**********************************************************************"<<endl;
cout<<"请选择设备号:";
cin>>inum;
while(inum < 1 || inum > i||usability[inum]==0)//提示用户输入选择的设备号
{
cout<<"输入有误,请重新输入:";
cin>>inum;
}
//***********************************下面取得本机网络信息************************************************
cout<<endl<<"*****************************本机网络信息*****************************";
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);// 跳转到已选设备
if ( (pt= pcap_open(d->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,errbuf) ) == NULL)// 打开适配器
{
cout<<"打开网络接口失败!"<<endl;
pcap_freealldevs(alldevs);
return -1;
}
if(pcap_datalink(pt) != DLT_EN10MB)//我们只研究以太网,不是以太网则退出
{
cout<<"您的网络不是以太网!"<<endl;
pcap_freealldevs(alldevs);
return -1;
}
cout<<endl<<endl<<"本网卡的IP地址: ";
for(pAdr=d->addresses;pAdr;pAdr=pAdr->next)//本循环用来搜索IP地址所有网段并发送ARP请求给本机
{
localip=((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr;//获得IP地址
nlNetMask=((struct sockaddr_in *)(pAdr->netmask))->sin_addr.S_un.S_addr;//获得子网掩码
cout<<(localip&255)<<"."<<(localip>>8&255)<<"."<<"."<<(localip>>16&255)<<"."<<(localip>>24&255)<<endl;//按用户熟悉的方式输出子网掩码
MakePacket(0x50505050,localip,&myPacket);//封装请求包,本机MAC地址先伪装成为0x50505050
if (pcap_sendpacket(pt, (unsigned char*)&myPacket, 60) != 0)//发送ARP请求包
{
cout<<"发送数据时出错!"<<endl;
}
}
bpf_program* filterCode = NULL;//下面开始设置过滤器
char* filterString = "ether protoarp";
if (-1 != pcap_compile(pt, filterCode, filterString, 1, 0xFFFF0000)) // 编译过滤器
{
pcap_setfilter(pt, filterCode);
}
for(;;) //接收本机的ARP响应主循环
{
int res = pcap_next_ex(pt, &pktHd, &pktDt);//接收回复包
if (res==1)
{ arp_packet* recv = (arp_packet*) pktDt;
if (htons(0x0806) != recv->eth.eh_type)// 判断是不是ARP包,则将其丢弃并重新接收
{
continue;
}
if (recv->arp.option==htons(0x0002)&& recv->arp.dest_ip == 0x50505050 && recv->arp.sour_ip == localip)//检查是不是发送给本机的,并且是不是回复包
{
memcpy(localmac, recv->arp.sour_addr, 6);
printf("本网卡MAC地址是: "); for(i=0;i<6;i++) printf("%x ",localmac[i]);
printf("\n");
pcap_close(pt);
break;
}
}
else if (0 == res) // 如果超时,则重新接收
{
continue;
}
else // 如果出错,则关闭WinPcap会话,然后返回
{
pcap_close(pt);
break;
}
}
HostNum=~ntohl(nlNetMask);//局域网内主机数目,根据掩码取得
iptosendh=ntohl(localip&nlNetMask);//第一个要发送ARP请求的IP地址(获得本机MAC后,将向所有可能的IP地址发arp请求)
//***********************************下面取得局域网主机MAC地址信息**********************************************
cout<<endl<<"***************************局域网内活动主机***************************"<<endl;
//下面创建一个接收线程和一个发送线程
CreateThread(NULL, 0, threadofrcv, NULL, 0, NULL);//创建接收线程
CreateThread(NULL, 0, threadofsnt, NULL, 0, NULL);//创建发包线程
Sleep(100);//主线程等一下,让两个子线程有时间运行起来
while (myThreadCou