WinPcap实战(二)——接收ARP包

ARP帧结构

ARP帧结构(28B):硬件类型(2B,Ethernet:0x1)——上层协议类型(2B,IP:0x0800)——硬件地址长度(1B,0x6)——IP地址长度(1B,0x4)——操作(2B,请求: 0x1; 应答: 0x2)——源MAC地址(6B)——源IP地址(6B)——目的MAC地址(6B)——目的IP地址(6B)

依据ARP帧结构定义结构体

struct ArpHeader
{
	unsigned short hdtyp;   //硬件类型
	unsigned short protyp;   //协议类型
	unsigned char hdsize;   //硬件地址长度
	unsigned char prosize;   //协议地址长度
	unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
	u_char smac[6];   //源MAC地址
	u_char sip[4];   //源IP地址
	u_char dmac[6];   //目的MAC地址
	u_char dip[4];   //目的IP地址
};

源代码

#include "stdafx.h"
#include "pcap.h"

struct ArpHeader
{
	unsigned short hdtyp;   //硬件类型
	unsigned short protyp;   //协议类型
	unsigned char hdsize;   //硬件地址长度
	unsigned char prosize;   //协议地址长度
	unsigned short op;   //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
	u_char smac[6];   //源MAC地址
	u_char sip[4];   //源IP地址
	u_char dmac[6];   //目的MAC地址
	u_char dip[4];   //目的IP地址
};

int main()
{
	pcap_if_t *alldevs;   //所有网络适配器  
	pcap_if_t *d;   //选中的网络适配器 
	int inum;   //选择网络适配器
	int i = 0;   //for循环变量
	pcap_t *adhandle;   //打开网络适配器,捕捉实例,是pcap_open返回的对象
	char errbuf[PCAP_ERRBUF_SIZE];   //错误缓冲区,大小为256
	int res;   //抓包函数pcap_next_ex返回值,1-成功、0:获取报文超时、-1:发生错误、-2: 获取到离线记录文件的最后一个报文
	u_int netmask;    //子网掩码
	//ether proto protocol:如果数据包属于某些以太协议(protocol)类型, 则与此对应的条件表达式为真,协议字段可以是ARP
	char packet_filter[] = "ether proto \\arp";   //要抓取的包的类型,这里是抓取ARP包;
	struct bpf_program fcode;   //pcap_compile所调用的结构体
	struct tm *ltime;   //和时间处理有关的变量 
	char timestr[16];   //和时间处理有关的变量
	time_t local_tv_sec;    //和时间处理有关的变量
	struct pcap_pkthdr *header;   //接收到的数据包的头部
	const u_char *pkt_data;    //接收到的数据包的内容
	

	/* 获取本机设备列表 */
	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");
		return -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);
		return -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, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
		/* 释放设列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/* 检查数据链路层,为了简单,我们只考虑以太网 */
	if (pcap_datalink(adhandle) != DLT_EN10MB)
	{
		fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	if (d->addresses != NULL)
		/* 获得接口第一个地址的掩码 */
		netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
	else
		/* 如果接口没有地址,那么我们假设一个C类的掩码 */
		netmask = 0xffffff;

	//编译过滤器
	if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)
	{
		fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	//设置过滤器
	if (pcap_setfilter(adhandle, &fcode) < 0)
	{
		fprintf(stderr, "\nError setting the filter.\n");
		/* 释放设备列表 */
		pcap_freealldevs(alldevs);
		return -1;
	}

	printf("\nlistening on %s...\n", d->description);

	/* 释放设备列表 */
	pcap_freealldevs(alldevs);

	/*以上代码在WinPcap开发文档中都可以找到,解析ARP包的代码则要自己编写*/

	/* 获取数据包 */
	while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {

		if (res == 0)
			/* 超时时间到 */
			continue;

		//解析ARP包
		ArpHeader* arph = (ArpHeader *)(pkt_data + 14);

		//类型 
		printf("报文类型:");
		if (arph->op == 256)
			printf("请求报文\t");
		else
			printf("应答报文\t");

		//长度
		printf("长度(B):%d\t", header->len);

		//时间
		/* 将时间戳转换成可识别的格式 */
		local_tv_sec = header->ts.tv_sec;
		ltime = localtime(&local_tv_sec);
		strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);

		printf("时间:%s\n", timestr);

		
		//输出源IP
		printf("源IP:");
		for (i = 0; i < 3; i++)
		{
			printf("%d.", arph->sip[i]);
		}
		printf("%d\t", arph->sip[3]);

		//输出目的IP
		printf("目的IP:");
		for (i = 0; i < 3; i++)
		{
			printf("%d.", arph->dip[i]);

		}
		printf("%d\n", arph->dip[3]);

		//输出源MAC
		printf("源MAC:");
		for (i = 0; i < 5; i++)
		{
			printf("%02x-", arph->smac[i]);
		}
		printf("%02x\t", arph->smac[5]);

		//输出目的MAC
		printf("目的MAC:");
		for (i = 0; i < 5; i++)
		{
			printf("%02x-", *(pkt_data + i));
		}
		printf("%02x\n", *(pkt_data + 5));
		
		printf("----------------------------我是一只分隔线-----------------------------\n");

	}

	if (res == -1) {   //接收ARP包出错
		printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
		return -1;
	}

	return 0;
}

运行结果

程序在VS2015企业版里面运行无误,需要提前配置好WinPcap的编程环境

选择第三个网卡,开始监听网络
这里写图片描述

等待几分钟后,抓取到ARP包
这里写图片描述

传送门

发送ARP包:
http://blog.csdn.net/u013539342/article/details/48523933#t4
参考网址:http://blog.csdn.net/cqcre/article/details/40213911
WinPcap编程配置:http://www.findspace.name/easycoding/871
VS下This function or variable may be unsafe解决办法:
http://jingyan.baidu.com/article/49711c616b8a1ffa441b7cdc.html

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ARP(Address Resolution Protocol)是一种网络协议,用于将IP地址映射到物理地址,以便在网络上发送数据。WinPcap是一个开源的网络抓包库,可以用于捕获和解析网络数据。下面是利用WinPcap解析ARP的步骤: 1. 安装WinPcap库并配置环境变量。 2. 创建一个WinPcap捕获器,并设置过滤器以仅捕获ARP数据。 ```c++ pcap_t* pcap_handle; char errbuf[PCAP_ERRBUF_SIZE]; struct bpf_program filter; pcap_handle = pcap_open_live("eth0", BUFSIZ, 1, 1000, errbuf); if (pcap_handle == NULL) { printf("Unable to open the adapter. %s is not supported by WinPcap\n", dev->name); return -1; } if (pcap_compile(pcap_handle, &filter, "arp", 1, PCAP_NETMASK_UNKNOWN) == -1) { printf("Error compiling filter expression: %s\n", pcap_geterr(pcap_handle)); return -1; } if (pcap_setfilter(pcap_handle, &filter) == -1) { printf("Error setting filter: %s\n", pcap_geterr(pcap_handle)); return -1; } ``` 3. 循环捕获ARP数据,并解析其中的源MAC地址、目的MAC地址、源IP地址和目的IP地址。 ```c++ struct pcap_pkthdr *header; const u_char *packet; struct ether_header *ethhdr; struct ether_arp *arphdr; while (pcap_next_ex(pcap_handle, &header, &packet) == 1) { ethhdr = (struct ether_header*)packet; arphdr = (struct ether_arp*)(packet + sizeof(struct ether_header)); if (ntohs(ethhdr->ether_type) == ETHERTYPE_ARP) { printf("Source MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ethhdr->ether_shost[0], ethhdr->ether_shost[1], ethhdr->ether_shost[2], ethhdr->ether_shost[3], ethhdr->ether_shost[4], ethhdr->ether_shost[5]); printf("Destination MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ethhdr->ether_dhost[0], ethhdr->ether_dhost[1], ethhdr->ether_dhost[2], ethhdr->ether_dhost[3], ethhdr->ether_dhost[4], ethhdr->ether_dhost[5]); printf("Source IP: %d.%d.%d.%d\n", arphdr->arp_spa[0], arphdr->arp_spa[1], arphdr->arp_spa[2], arphdr->arp_spa[3]); printf("Destination IP: %d.%d.%d.%d\n", arphdr->arp_tpa[0], arphdr->arp_tpa[1], arphdr->arp_tpa[2], arphdr->arp_tpa[3]); } } ``` 4. 关闭捕获器并释放资源。 ```c++ pcap_close(pcap_handle); ``` 以上就是利用WinPcap解析ARP的基本步骤。需要注意的是,WinPcap只能在Windows平台上使用,而且需要管理员权限才能运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值