WinPcap实战(一)——发送ARP包

ARP包的结构:

  1. ARP包格式:物理帧头(14B)——ARP帧结构(28B)——填充数据(18B)——CRC(4B)。这里给出一张图(图中没有18字节的填充数据和4字节的校验位):这里写图片描述

  2. 物理帧头(14B):目的MAC (6B) ——源MAC(6B) ——类型(2B, ARP帧:0x0806)

  3. 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包的结构定义结构体

//14字节以太网首部
struct EthernetHeader
{
	u_char DestMAC[6];    //目的MAC地址 6字节
	u_char SourMAC[6];   //源MAC地址 6字节
	u_short EthType;         //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp  2字节
};

//28字节ARP帧结构
struct ArpHeader
{
	unsigned short hdType;   //硬件类型
	unsigned short proType;   //协议类型
	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地址
};

//定义整个arp报文包,总长度42字节
struct ArpPacket {
	EthernetHeader ed;
	ArpHeader ah;
};

源代码

#include "stdafx.h"

#include <pcap.h>

#define ETH_ARP         0x0806  //以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
#define ARP_HARDWARE    1  //硬件类型字段值为表示以太网地址
#define ETH_IP          0x0800  //协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
#define ARP_REQUEST     1   //ARP请求
#define ARP_RESPONSE       2      //ARP应答

//14字节以太网首部
struct EthernetHeader
{
	u_char DestMAC[6];    //目的MAC地址 6字节
	u_char SourMAC[6];   //源MAC地址 6字节
	u_short EthType;         //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp  2字节
};

//28字节ARP帧结构
struct ArpHeader
{
	unsigned short hdType;   //硬件类型
	unsigned short proType;   //协议类型
	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地址
};

//定义整个arp报文包,总长度42字节
struct ArpPacket {
	EthernetHeader ed;
	ArpHeader ah;
};


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

	/* 获取本机设备列表 */
	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;
	}

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

	//开始填充ARP包,填充数据写死在代码中,测试用时数据可随意填写
	unsigned char sendbuf[42]; //arp包结构大小,42个字节
	unsigned char mac[6] = { 0x00,0x11,0x22,0x33,0x44,0x55 };
	unsigned char ip[4] = { 0x01,0x02,0x03,0x04 };
	EthernetHeader eh;
	ArpHeader ah;
	//赋值MAC地址
	memset(eh.DestMAC, 0xff, 6);   //以太网首部目的MAC地址,全为广播地址
	memcpy(eh.SourMAC, mac, 6);   //以太网首部源MAC地址
	memcpy(ah.smac, mac, 6);   //ARP字段源MAC地址
	memset(ah.dmac, 0xff, 6);   //ARP字段目的MAC地址
	memcpy(ah.sip, ip, 4);   //ARP字段源IP地址
	memset(ah.dip, 0x05, 4);   //ARP字段目的IP地址
	eh.EthType = htons(ETH_ARP);   //htons:将主机的无符号短整形数转换成网络字节顺序
	ah.hdType = htons(ARP_HARDWARE);
	ah.proType = htons(ETH_IP);
	ah.hdSize = 6;
	ah.proSize = 4;
	ah.op = htons(ARP_REQUEST);

	//构造一个ARP请求
	memset(sendbuf, 0, sizeof(sendbuf));   //ARP清零
	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());
	}

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

	return 0;
}

运行结果

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

选择第三个网卡,成功发送ARP包
这里写图片描述

抓包软件抓到ARP包:
这里写图片描述

传送门

接收ARP包:
http://blog.csdn.net/u013539342/article/details/48525525
参考网址: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

  • 9
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
很抱歉,作为AI语言模型,我没有权限编写代码。但是,我可以为您提供一些关于使用WinPcap发送ARP数据的基本信息。 WinPcap是一个用于Windows平台的网络数据捕获库,它可以捕获和发送数据。以下是使用WinPcap发送ARP数据的基本步骤: 1. 打开WinPcap: ```c pcap_t *adhandle; adhandle = pcap_open_live(device, 65536, 1, 1000, errbuf); ``` 其中,device是要使用的网络设备,例如“eth0”或“wlan0”。65536是要捕获的数据的最大大小,1是指要开启混杂模式(即捕获所有流经网络设备的数据),1000是指超时时间(以毫秒为单位),errbuf是一个缓冲区,用于存储错误信息。 2. 构造ARP数据: ```c char packet[42]; // ARP数据的大小为42个字节 memset(packet, 0, sizeof(packet)); // 清零 struct ether_header *eth_header = (struct ether_header *) packet; struct ether_arp *arp_header = (struct ether_arp *) (packet + sizeof(struct ether_header)); // 填充以太网头部 eth_header->ether_dhost[0] = 0xff; eth_header->ether_dhost[1] = 0xff; eth_header->ether_dhost[2] = 0xff; eth_header->ether_dhost[3] = 0xff; eth_header->ether_dhost[4] = 0xff; eth_header->ether_dhost[5] = 0xff; eth_header->ether_shost[0] = 0x00; // 发送方MAC地址 eth_header->ether_shost[1] = 0x11; eth_header->ether_shost[2] = 0x22; eth_header->ether_shost[3] = 0x33; eth_header->ether_shost[4] = 0x44; eth_header->ether_shost[5] = 0x55; eth_header->ether_type = htons(ETHERTYPE_ARP); // ARP数据类型 // 填充ARP头部 arp_header->arp_hrd = htons(ARPHRD_ETHER); // 以太网硬件类型 arp_header->arp_pro = htons(ETHERTYPE_IP); // IP协议类型 arp_header->arp_hln = 6; // MAC地址长度为6字节 arp_header->arp_pln = 4; // IP地址长度为4字节 arp_header->arp_op = htons(ARPOP_REQUEST); // ARP请求操作 arp_header->arp_sha[0] = 0x00; // 发送方MAC地址 arp_header->arp_sha[1] = 0x11; arp_header->arp_sha[2] = 0x22; arp_header->arp_sha[3] = 0x33; arp_header->arp_sha[4] = 0x44; arp_header->arp_sha[5] = 0x55; arp_header->arp_spa[0] = 192; // 发送方IP地址 arp_header->arp_spa[1] = 168; arp_header->arp_spa[2] = 1; arp_header->arp_spa[3] = 1; arp_header->arp_tha[0] = 0x00; // 目标MAC地址(未知) arp_header->arp_tha[1] = 0x00; arp_header->arp_tha[2] = 0x00; arp_header->arp_tha[3] = 0x00; arp_header->arp_tha[4] = 0x00; arp_header->arp_tha[5] = 0x00; arp_header->arp_tpa[0] = 192; // 目标IP地址 arp_header->arp_tpa[1] = 168; arp_header->arp_tpa[2] = 1; arp_header->arp_tpa[3] = 2; ``` 在上面的示例中,我们构造了一个ARP请求数据,用于获取192.168.1.2的MAC地址。可以根据需要更改目标IP地址和发送方MAC地址。 3. 发送ARP数据: ```c int res; res = pcap_sendpacket(adhandle, packet, sizeof(packet)); if (res != 0) { printf("Error sending ARP packet: %s\n", pcap_geterr(adhandle)); } ``` 在上面的示例中,我们使用pcap_sendpacket函数发送构造的ARP数据,如果发送失败,则会打印错误信息。 希望以上信息能够帮助您编写WinPcap发送ARP数据的程序。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值