//基于ARP协议
//实现获取本局域网内全部活动主机MAC地址与IP地址对应关系列表的程序;
#include<pcap.h>
#include<iostream.h>
#include<remote-ext.h>
#include<stdio.h>
#include<memory.h>
#include<string.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <winsock.h>
#endif
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "wpcap.lib")
//DLC头数据结构;
struct DlcHeader
{
unsigned char DesMac[6]; //目的MAC地址;
unsigned char SourMac[6]; //源MAC地址;
unsigned short Ethertype; //以太网类型;
};
//ARP帧数据结构;
struct ArpFrame
{
unsigned short HW_Type; //硬件类型;
unsigned short IP_Type; //上层协议类型;
unsigned char HW_Addr_Len; // 硬件地址长度;
unsigned char IP_Addr_Len; //IP地址长度;
unsigned short nFlag; //操作类型,1表示请求,2表示应答;
unsigned char Sour_HW_Type[6]; //源MAC地址;
unsigned char Sour_IP_Type[4]; // 源IP地址;
unsigned char Tag_HW_Type[6]; //目的MAC地址;
unsigned char Tag_IP_Type[4]; //目的IP地址;
unsigned char Fill_data[18]; //填充字段;
};
//最终的ARP包结构;
struct ArpStruct
{
DlcHeader eth_section;
ArpFrame arp_section;
};
typedef unsigned char uchar;
// 将数字类型的IP地址转换成字符串类型的,易于阅读;
#define IPTOSBUFFERS 12
//函数原型;
uchar SOURCEMAC[6];//全局变量保存本机的物理地址;
void sendarp(pcap_t *,uchar*,uchar*,uchar*,short,int);
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
//将IP地址转换成易于阅读的字符串形式;
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;
p = (u_char *)∈
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}
//用自己给自己发包,获得自己的MAC,用全局变量SOURCEMAC保存;
void GetSouMac(char* pDevName, uchar*chLocalIP)
{
char errbuf[PCAP_ERRBUF_SIZE ];
pcap_t *adhandle;
if(( adhandle=pcap_open(pDevName, // 设备名
60, // 要捕捉的arp数据包是60个字节;
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
100, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
) ) == NULL){
cout<<"不能打开适配器"<<endl;
exit(1);
}
uchar source_mac[6] = {0,0,0,0,0,0};
uchar myIP[4];//定义获得自己MAC地址的特殊源IP,112.112.112.112
for(int i=0;i<4;i++)
myIP[i]=0x70;
sendarp(adhandle,source_mac,myIP, chLocalIP,(short)chLocalIP[3],60);//给自己发包;
pcap_dispatch(adhandle, 0, packet_handler, NULL);//捕获自己发给自己的包;
}
//封装、发送并捕获ARP数据包;
void sendarp(pcap_t *adhandle,uchar*SoucMac,uchar* SoucIP,uchar*net_seq,short size,int PackSize)
{
ArpStruct ArpReq; //定义要发送的ARP数据包;
for(int i=0;i<6;i++)
{
ArpReq.eth_section.DesMac[i]=0xFF; //广播地址;
ArpReq.arp_section.Tag_HW_Type[i]=0x00;
}
memcpy(ArpReq.eth_section.SourMac,SoucMac,6);
ArpReq.eth_section.Ethertype =htons(0x0806);
ArpReq.arp_section.HW_Type=htons(0x0001);
ArpReq.arp_section.IP_Type=htons(0x0800);
ArpReq.arp_section.HW_Addr_Len=0x06;
ArpReq.arp_section.IP_Addr_Len=0x04;
ArpReq.arp_section.nFlag=htons(0x0001);
memcpy(ArpReq.arp_section.Sour_HW_Type,SoucMac,6);
memcpy(ArpReq.arp_section.Sour_IP_Type,SoucIP,4);
memcpy(ArpReq.arp_section.Tag_IP_Type,net_seq,4);
ArpReq.arp_section.Tag_IP_Type[3]=size;
for(int m=0;m<18;m++)
ArpReq.arp_section.Fill_data [m]=0;
if (pcap_sendpacket(adhandle, (uchar*)&ArpReq, 60) != 0)//发送arp请求数据包;
{
fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(adhandle));
exit(1);
}
}
//主函数部分;
void main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *a;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
//获取本机设备列表;
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
//打印列表
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
exit(1);
}
printf("Enter the interface number (1-%d):",i);//用户输入选择设备列表;
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");// 释放设备列表;
pcap_freealldevs(alldevs);
exit(1);
}
// 跳转到选中的适配器 ;
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
a=d->addresses;
if(a->addr->sa_family==AF_INET)
{
if (a->addr) //打印IP地址;
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)//打印子网掩码;
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr) //打印广播地址;
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
}
printf("\n");
//获取并输出本机的IP地址;
uchar soucIP[4];
cout<<"本地ip地址: ";
soucIP[0]=((struct sockaddr_in *)(d->addresses->addr))->sin_addr.S_un.S_un_b.s_b1;
soucIP[1]=((struct sockaddr_in *)(d->addresses->addr))->sin_addr.S_un.S_un_b.s_b2;
soucIP[2]=((struct sockaddr_in *)(d->addresses->addr))->sin_addr.S_un.S_un_b.s_b3;
soucIP[3]=((struct sockaddr_in *)(d->addresses->addr))->sin_addr.S_un.S_un_b.s_b4;
for(i=0;i<4;i++)
cout<<(short)soucIP[i]<<".";
cout<<endl;
//获得本地局域网的子网掩码;
uchar netmask[4];
if(d->addresses != NULL)
{
netmask[0]=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_un_b.s_b1;
netmask[1]=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_un_b.s_b2;
netmask[2]=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_un_b.s_b3;
netmask[3]=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_un_b.s_b4;
}
//如果接口没有地址,那么我们假设一个C类的掩码
else
{
netmask[0]=0xff;
netmask[1]=0xff;
netmask[2]=0xff;
netmask[3]=0x00;
}
//调函数得到本机的物理地址;
GetSouMac(d->name,soucIP);
if ( (adhandle= pcap_open(d->name, // 设备名;
60, // 要捕捉的arp数据包长度;
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
6, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 释放设列表 */
pcap_freealldevs(alldevs);
exit(1) ;
}
//获取本地局域网的网络号;
uchar net_seq[4];
cout<<"本地局域网的网络号:";
for(i=0;i<4;i++)
{
net_seq[i]=soucIP[i]&netmask[i];
cout<<dec<<(short)net_seq[i]<<".";
}
cout<<endl;
uchar netsize = 0; //记录局域网可能的最大主机数;
netsize = ~net_seq[3];
cout<<"本局域网内可能有的主机数是:"<<dec<<(short)netsize<<endl;
//为了防止丢包,发送arp数据包的时候就进行捕获;
for(short n=0;n<=netsize;n++)
{
sendarp(adhandle,SOURCEMAC,soucIP,net_seq,n,60);
pcap_dispatch(adhandle, 0, packet_handler, NULL);
}
pcap_freealldevs(alldevs);//释放设备列表;
}
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pk