#include<stdio.h>
#include<string.h>
#include"pcap.h"
#include"Packet32.h"
#pragma pack(1)  //按一个字节内存对齐
#define IPTOSBUFFERS  12
#define ETH_ARP       0x0806 //以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为0x0806
#define ARP_HARDWARE  1      //硬件类型字段值表示以太网地址
#define ETH_IP        0x0800 //协议类型字段表示要映射的协议地址,类型值为0x0800表示IP地址
#define ARP_REQUEST   1
#define ARP_REPLY     2
#define HOSTNUM       255
/*packet handler 函数原型*/
void packet_handler(u_char *param,const struct pcap_pkthdr *header,const u_char *pkt_data);
//函数原型
void ifget(pcap_if_t*d,char *ip_addr,char ip_netmask);
char *iptos(u_long in);
char *ip6tos(struct sockaddr *sockaddr,char *address,int addrlen);
int SendArp(pcap_t *adhandle,char *ip,unsigned char *mac);
int GetSelfMac(pcap_t *adhandle,const *ip_addr,unsigned char *ip_mac);
DWORD WINAPI SendArpPacket(LPVOID lpParameter);
DWORD wINAPI GetLivePC(lPVOID IpParameter);
//28字节ARP帧结构
struct arp_head
{
	unsigned short hardware_type;    //硬件类型
	unsigned short protocol_type;    //协议类型
	unsigned char hardware_add_len;  //硬件地址长度
	unsigned char protocol_add_len;  //协议地址长度
	unsigned short operation_field;  //操作字段
	unsigned char source_mac_add[6]; //源MAC地址
	unsigned long source_ip_add;     //源IP地址
	unsigned char dest_mac_add[6];   //目的MAC地址
	unsigned long dest_ip_add;       //目的IP地址
};
//14字节以太网帧结构
struct ethernet_head
{
	unsigned char dest_mac_add[6];//目的MAC地址
	unsigned char source_mac_add[6];//源MAC地址
	unsigned short type;//帧类型
};
//ARP最终包结构
struct arp_packet
{
	struct ethernet_head ed;
	struct arp_head ah;
};
struct sparam
{
	pcap_t *adhandle;
	char *ip;
	unsigned char *mac;
	char *netmask;
};
struct gparam
{
	pacp_t *adhandle;
};
bool flag;
struct sparam sp;
struct gparam gp;

int main()
{
	pacp_if_t *alldevs;
	pacp_if_t *d;
	int inum;
	int i=0;
	pacp_t *adhandle;
	char errbuf[PCAP_ERRBUF_SIZE];
	char *ip_addr;
	char *ip_netmask;
	unsigned char *ip_mac;
	HANDLE sendthread;
	HANDLE recnthread;

	ip_addr=(char *)malloc(sizeof(char)*16);
	if(ip_addr==NULL)
	{
		printf("申请内存存放IP地址失败!\n");       //申请内存存放IP地址
		return -1;
	}
	ip_netmask=(char *)malloc(sizeof(char)*16);
	if(ip_netmask=NULL)
	{
		printf("申请内存存放NETMASK地址失败\n");     //申请内存存放NETMASK地址
		return -1;
	}
	ip_mac=(unsigned char *)malloc(sizeof(unsigned char)*6);
	if(ip_mac==NULL)
	{
		printf("申请内存存放MAC地址失败!\n");
		return -1;
	}
	/*获取本机设备列表*/
	if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1)
	{
		fprintf(stderr,"Error in pcap_findalldevs:%s\n",errbuf);
		exit(1);
	}
	/*打印列表*/
	printf("[本机网卡列表:]\n");
	for(d=alldevs;d;d=d->next)
	{
		printf("%d)%s\n",++i,d->name);
		if(d->description)
			printf("(%s)\n",d->description);
		else
			printf("(No description available)\n");
	}
	if(i==0)
	{
		printf("\n找不到网卡!请确认是否已安装WinPcap.\n");
		return -1;
	}
	printf("\n");
	printf("请选择要打开的网卡号(1-%d):",i);
	scanf("%d",&inum);
	if(inum<1||inum>i)
	{
		printf("\n 该网卡号超过现有网卡数!请按任意键退出...\n");
		getchar();
		getchar();
		/*释放设备列表*/
		pcap_freealldevs(alldevs);
		retrun -1;
	}
	/*跳转到选中的适配器*/
	for(d=alldevs,i=0;i<inum-1;d=d->next,i++);
	/*打开设备*/
	if((adhandle=pcap_open(d->name,//设备名
		65536,                     //65535保证能捕获到不同数据链路层上的每个数据包的全部内容
		PCAP_OPENFLAG_PROMISCUOUS, //混杂模式
		1000,                      //读取超时时间
		NULL,		               //远程机器验证
		errbuf                     //错误缓冲池
		))==NULL)
		{
			fprintf(stderr,"\n无法读取该适配器,适配器%s,不被WinPcap支持\n",d->name);
			/*释放设备列表*/
			pcap_freealldevs(alldevs);
			retrurn -1;
		}
		ifget(d,ip_addr,ip_netmask);//获取所选网卡的基本信息-掩码-地址
		GetSelfMac(adhandle,ip_addr,ip_mac);//输入网卡设备句柄网卡设IP地址获取该设备的MAC地址
		sp.adhandle=adhandle;
		sp.ip=ip_addr;
		sp.mac=ip_mac;
		sp.netmask=ip.netmask;
		gp.adhandle=adhandle;
		sendthread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendArpPacket,&sp,0,NULL);
		recvthread=CreateThread(NULL,0,(lpTHREAD_START_ROUTINE)GetLivePC,&gp,0,NULL);
		printf("\nlistening on 网卡%d...\n",inum);
		/*释放设备列表*/
		pcap_freealldevs(alldevs);
		getchar();
		getchar();
		return 0;
}
/*获取可用信息*/
void ifget(pcap_if_t *d,char *ip_addr,char *ip_netmask)
{
	pcap_addr_t *a;
	char ip6str[128];
	/*IP addresses*/
	for(a=d->addresses,a;a=a->next)
	{
		switch(a->addr->sa_family)
		{
			case AF_INET;
			if(a->addr)
			{
				char *ipstr;
				ipstr=iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr);//*ip_addr
				memcpy(ip_addr,ipstr,16);
			}
			if(a->netmask)
			{
				char *netmaskstr;
				netmaskstr=iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr);
				memcpy(ip_netmask,netmaskstr,16);
			}
			case AF_INET6;
			break;
		}
	}
}
/*将数字类型的IP地址转换成字符串类型*/
char *iptos(u_long in)
{
	static char output[IPTOSBUFFERS][3*4+3+1];
	static short which;
	u_char *p;
	p=(u_char *)&in;
	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];
}
char *ip6tos(struct sockaddr *sockaddr,char *address,int addrlen)
{
	socklen_t sockaddrlen;
    #ifdef WIN32
	sockaddrlen=sizeof(struct sockaddr_in6);
    #else
	sockaddrlen=sizeof(struct sockaddr_storage);
    #endif

	if(getnameinfo(sockaddr,sockaddrlen,address,addrlen,NULL,0,NI_NUMERICHOST)!=0)
		address=NULL;
	return address;
}
/*获取自己主机的MAC地址*/
int GetSelfMac(pcap_t *adhandle,const *ip_addr,unsigned char *ip_mac)
{
	unsigned char sendbuf[42];//ARP包结构大小
	int i=-1;
	int res;
	struct ethernet_head eh;
	struct arp_head ah;
	struct pcap_pkthdr *pkt_header;
	const u_char *pkt_data;
	memset(eh.dest_mac_add,0xff,6);//目的地址全为广播地址
	memset(eh.source_mac_add,0x0f,6);
	memset(ah.source_mac_add,0x0f,6);
	memset(ah.dest_mac_add,0x00,6);
	th.type=htons(ETH_ARP);
	ah.hardware_type=htons(ARP_HARDWARE);
	ah.protocol_type=htons(ETH_IP);
	ah.hardware_add_len=6;
	ah.protocol_add_len=4;
	ah.source_ip_add=inet_addr("100.100.100.100");//随便设的请求方IP
	ah.operation_field=htons(ARP_REQUEST);
	ah.dest_ip_add=inet_addr(ip_addr);
	memset(sendbuf,0,sizeof(sendbuf));
	memcpy(sendbuf,&eh,sizeof(eh));
	memcpy(sendbuf+sizeof(eh),&ah,sizeof(ah));
	if(pcap_sendpacket(adhandle,sendbuf,42)==0)
	{
		printf("\nPacketSend succeed\n");
	}
	else
	{
		printf("PacketSendPacket in getmine Error:%d\n",GetLastError());
		return 0;
	}
	while((res=pcap_next_ex(adhandle,&pkt_header,&pkt_data))>=0)
	{
		if(*(unsigned short *)(pkt_data+12)==htons(ETH_ARP)&&*(unsigned short *)(pkt_data+20)==htons(ARP_REPLY)&&*(unsigned long *)(pkt_data+38)==inet_addr("100,100,100,100"))
		{
			for(i=0;i<6;i++)
			{
				ip_mac[i]=*(unsigned char *)(pkt_data+22+i);
			}
			printf("获取自己主机的MAC地址成功!\n");
			break;
		}
	}
	if(i==6)
	{
		return 1;
	}
	else
	{
		return 0;
	}

}
/*向局域网内所有可能的IP地址发送ARP请求包线程*/
DWORD WINAPI SendArpPacket(LPVOID lpParameter)//(pcap_t *adhandle,char *ip,unsigned char *mac,char *netmask)
{
	sparam *spara=(sparam *)lpParameter;
	pcap_t *adhandle=spara->adhandle;
	char *ip=spara->ip;
	unsigned char *mac=spara->mac;
	char *netmask=spara->netmask;
	printf("ip_mac:%02x-%02x-%02x-%02x-%02x-%02x\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
	printf("自身的IP地址为:%s\n",ip);
	printf("地址掩码NETMASK为:%s\n",netmask);
	printf("\n");
	unsigned char sendbuf[42];//arp包结构大小
	struct ethernet_head eh;
	struct arp_head ah;
	memset(eh.dest_mac_add,0xff,6);//目的地址全为广播地址
	memcpy(eh.source_mac_add,mac,6);
	memcpy(ah.source_mac_add,mac,6);
	memset(ah.dest_mac_add,0x00,6);
	eh.type=htons(ETH_ARP);
	ah.hardware_type=htons(ARP_HARDWARE);
	ah.protocol_type=htons(ETH_IP);
	ah.hardware_add_len=6;
	ah.protocol_add_len=4;
	ah.source_ip_add=inet_addr(ip);//请求方的IP地址为自身的IP地址
	ah.operation_field=htons(ARP_REQUEST);
	//向局域网内广播发送ARP包
	unsigned long myip=inet_addr(ip);
	unsigned long mynetmask=inet_addr(netmask);
	unsigned long hisip=htonl((myip&mynetmask));
	for(int i=0;i<HOSTNUM;i++)
	{
		ah.dest_ip_add=hton(hisip+i);
		memset(sendbuf,0,sizeof(sendbuf));
		memcpy(sendbuf,&eh,sizefo(eh));
		memcpy(sendbuf+sizeof(eh),&ah,sizeof(ah));
		if(pcap_sendpacket(adhandle,sendbuf,42)==0)
		{
			//printf("\nPacketSend succed\n");
		}
		else
		{
			printf("PacketSendPacket in getmine Error:%d\n",GetLastError());
		}
		Sleep(50);
	}
	Sleep(1000);
	flag=TRUE;
	return 0;
}
/*分析截留的数据包获取活动的主机IP地址*/
DWORD WINAPI GetLivePc(LPVOID lpParameter)//(pcap_t *adhandle)
{
	gparam *gpara=(gparam *)lpParameter;
	pcap_t *adhandle=gpara->adhandle;
	const u_char *pkt_data;
	while(true)
	{
		if(flag)
		{
			printf("扫描完毕,按任意键退出!\n");
			break;
		}
		if((res=pcap_next_ex(adhandle,&pkt_header,&pkt_data))>=0)
		{
			if(*(unsigned short *)(pkt_data+20)==htons(ARP_REPLY))
			{
				struct arp_packet *recv=(arp_packet *)pkt_data;
				if(*(unsigned short *)(pkt_data+20)==htons(ARP_REPLY))
				{
					printf("--------------------------------------\n");
					printf("IP地址:%d.%d.%d.%d       MAC地址:",recv->ah.source_ip_add&255,recv->ah.source_ip_add>>8&255,recv->ah.source_ip_add>>24&255);
					for(int i=0;i<6;i++)
					{
						Mac[i]=*(unsigned char *)(pkt_data+22+i);
						printf("%02x",Mac[i]);
					}
					printf("\n");
				}
			}		
		}
		Sleep(10);
	}
	return 0;
}