ARP协议(4)ARP编程

之前的几篇文章,分别介绍了 ARP 协议格式,在vs2012里配置winpcap环境,我们该做的准备都已经做完了,现在我们真正来实现了。

一、定义数据结构

根据ARP的协议格式,设计一个ARP协议格式

根据ARP的分组格式,我们知道它有两部分组成:

1、以太网首部,这是数据包在数据链路层上传输所必不可缺的部分,它的后面跟着相关的协议数据包(ARP/IP等)

2、ARP数据包

所以,我们有这么几个数据结构:

// 以太网的首部
typedef struct EthHead
{
 u_char dest_mac[6];	 // 以太网的目的地址
 u_char src_mac[6];	 // 以太网的源地址
 u_char type[2];	 // 帧类型 ARP:0x0806
}EthHead;
// ARP数据包
typedef struct ArpMsg
{
 u_char mac_type[2];	 // 硬件类型 以太网: 1
 u_char protocal_type[2];	// 协议类型 IP地址:0x0800
 u_char mac_len;	 // 硬件地址长度 6
 u_char protocal_len;	// 协议地址长度 4
 u_char op[2];	 // 操作字段 ARP请求:1 ARP应答:2 RARP请求:3 RARP应答:4
 u_char sender_mac[6];	// 发送端以太网地址
 u_char sender_ip[4];	// 发送端IP地址
 u_char target_mac[6];	// 目的以太网地址
 u_char target_ip[4];	// 目的IP地址
}ArpMsg;
// 以太网ARP
typedef struct Arp
{
 EthHead eth_head;
 ArpMsg arpmsg;
}Arp;

每个数据结构都有注释说明

注:

【1】由于网络数据传输都是大端模式,所以在设计这些数据结构,以及在封装数据的时候,注意要把本地序转为网络序

【2】为了方便,我把所有的字段类型都设为u_char(unsigned char)型,在封装数据的时候,只要按字节赋值,就不需要在进行本地序和网络序的转换了(如果是多字节存储,如short、int等,切记要进行转换)

二、组包

/*
	函数名: PacketArp
	功	能: 封装ARP包
	参  数:
		arp_req  : Arp类型,出参
		op		 : 操作字段
				   ARP请求:1
				   ARP响应:2
				   RARP请求:3
				   RARP相应:4
		dest_mac : 以太网目的地址
		src_mac	 : 以太网源地址
		sender_mac:发送端以太网地址
		sender_ip : 发送端IP地址
		target_mac: 目的以太网地址
		target_ip : 目的IP地址
	返  回: 0正确,-1错误

*/
int PacketArp(Arp *arp_req, u_char op, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
						 u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
	if(arp_req == NULL)
		return -1;
	memcpy(arp_req->eth_head.dest_mac, dest_mac, 6);
	memcpy(arp_req->eth_head.src_mac, src_mac, 6);
	arp_req->eth_head.type[0] = 0x08;
	arp_req->eth_head.type[1] = 0x06;
	//arp_req->eth_head.type = htons(arp_req->eth_head.type);

	arp_req->arpmsg.mac_type[0] = 0x00;
	arp_req->arpmsg.mac_type[1] = 0x01;
	arp_req->arpmsg.protocal_type[0] = 0x08;
	arp_req->arpmsg.protocal_type[1] = 0x00;
	arp_req->arpmsg.mac_len = 0x06;
	arp_req->arpmsg.protocal_len = 0x04;
	arp_req->arpmsg.op[0] = 0x00;
	arp_req->arpmsg.op[1] = op;
	memcpy(arp_req->arpmsg.sender_mac, sender_mac, 6);
	memcpy(arp_req->arpmsg.sender_ip, sender_ip, 4);
	memcpy(arp_req->arpmsg.target_mac, target_mac, 6);
	memcpy(arp_req->arpmsg.target_ip, target_ip, 4);

	return 0;
}

// ARP 请求包
int PacketArpRequest(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
<span style="white-space:pre">						</span> u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
<span style="white-space:pre">	</span>return PacketArp(arp_req,0x01,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}

// ARP 响应包
int PacketArpReplay(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
<span style="white-space:pre">						</span> u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
<span style="white-space:pre">	</span>return PacketArp(arp_req,0x02,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}

三、发包

/*
	功能: src_mac 向局域网广播:target_ip 192.168.1.111 的 mac 是多少
*/
int Text1(Arp *arp)
{
	u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};// 广播
	u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};// 源mac地址 F0-7B-CB-A3-15-85
	u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85}; // 发送端mac F0-7B-CB-A3-15-85
	u_char sender_ip[4] = {0xC0,0xA8,0x01,0x65}; //发送端IP地址 192.168.1.101
	u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; // 因为不知道mac,所以mac为空
	u_char target_ip[4] = {0xC0,0xA8,0x01,0x6F}; // 目的端ip 192.168.1.111;

	if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
	{
		printf("Packet arp request error\n");
		return -1;
	}
	return 0;
}
 Arp arp;
 if(Text1(&arp) == -1)
 {
  return ;
 }
 memcpy(packet, (void*)&arp, ARP_LEN);
 /* Send down the packet */
 if (pcap_sendpacket(fp, packet, ARP_LEN /* size */) != 0)
 {
  fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
  return;
 }

注:pcap_sendpacket 是winpcap里面的发包函数,此函数不支持linux

至此,我们的ARP组包、发包就完成了,就是这么简单(winpcap的功劳),下面我们用wireshark来抓包,看我们的包有没有发送出去。

从抓包来看,我们的包已经正确发出去了(192.168.1.111是我本机的ip),而且从还可以看出,已经有回包了,回包的具体内容:

我们再来对比下请求包和响应包的区别:

不言而喻吧

同时,我们再看下我们本地的ARP缓存:

192.168.1.111这台机器的IP和MAC映射也就加入到ARP高速缓存了。

附源码:

#include <stdlib.h>
#include <stdio.h>

// pcap_findalldevs_ex
#define HAVE_REMOTE
#include <pcap.h>

#define ARP_LEN 42

// 以太网的首部
typedef struct EthHead
{
	u_char dest_mac[6];		// 以太网的目的地址
	u_char src_mac[6];		// 以太网的源地址
	u_char type[2];			// 帧类型 ARP:0x0806
}EthHead;

// ARP数据包
typedef struct ArpMsg
{
	u_char mac_type[2];		// 硬件类型 以太网: 1
	u_char protocal_type[2];	// 协议类型 IP地址:0x0800
	u_char mac_len;			// 硬件地址长度 6
	u_char protocal_len;	// 协议地址长度 4
	u_char op[2];				// 操作字段 ARP请求:1 ARP应答:2 RARP请求:3 RARP应答:4
	u_char sender_mac[6];	// 发送端以太网地址
	u_char sender_ip[4];	// 发送端IP地址
	u_char target_mac[6];	// 目的以太网地址
	u_char target_ip[4];	// 目的IP地址
}ArpMsg;

// 以太网ARP
typedef struct Arp
{
	EthHead eth_head;
	ArpMsg arpmsg;
}Arp;

/*
	函数名: PacketArp
	功	能: 封装ARP包
	参  数:
		arp_req  : Arp类型,出参
		op		 : 操作字段
				   ARP请求:1
				   ARP响应:2
				   RARP请求:3
				   RARP相应:4
		dest_mac : 以太网目的地址
		src_mac	 : 以太网源地址
		sender_mac:发送端以太网地址
		sender_ip : 发送端IP地址
		target_mac: 目的以太网地址
		target_ip : 目的IP地址
	返  回: 0正确,-1错误

*/
int PacketArp(Arp *arp_req, u_char op, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
						 u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
	if(arp_req == NULL)
		return -1;
	memcpy(arp_req->eth_head.dest_mac, dest_mac, 6);
	memcpy(arp_req->eth_head.src_mac, src_mac, 6);
	arp_req->eth_head.type[0] = 0x08;
	arp_req->eth_head.type[1] = 0x06;
	//arp_req->eth_head.type = htons(arp_req->eth_head.type);

	arp_req->arpmsg.mac_type[0] = 0x00;
	arp_req->arpmsg.mac_type[1] = 0x01;
	arp_req->arpmsg.protocal_type[0] = 0x08;
	arp_req->arpmsg.protocal_type[1] = 0x00;
	arp_req->arpmsg.mac_len = 0x06;
	arp_req->arpmsg.protocal_len = 0x04;
	arp_req->arpmsg.op[0] = 0x00;
	arp_req->arpmsg.op[1] = op;
	memcpy(arp_req->arpmsg.sender_mac, sender_mac, 6);
	memcpy(arp_req->arpmsg.sender_ip, sender_ip, 4);
	memcpy(arp_req->arpmsg.target_mac, target_mac, 6);
	memcpy(arp_req->arpmsg.target_ip, target_ip, 4);

	return 0;
}

// ARP 请求包
int PacketArpRequest(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
						 u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
	return PacketArp(arp_req,0x01,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}

// ARP 响应包
int PacketArpReplay(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
						 u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
	return PacketArp(arp_req,0x02,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}

// 打开网络适配器
pcap_if_t* choose_interface()
{
	pcap_if_t *alldevs;
	pcap_if_t *d;
	int inum;
	int i=0;
	char errbuf[PCAP_ERRBUF_SIZE];

    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* Print the list */
    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 NULL;
    }

    printf("Enter the interface number (1-%d):",i);
    scanf_s("%d", &inum);

    if(inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return NULL;
    }

    /* Jump to the selected adapter */
    for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

    return d;
}

/*
	功能: src_mac 向局域网广播:target_ip 192.168.1.111 的 mac 是多少
*/
int Text1(Arp *arp)
{
	u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};// 广播
	u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};// 源mac地址 F0-7B-CB-A3-15-85
	u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85}; // 发送端mac F0-7B-CB-A3-15-85
	u_char sender_ip[4] = {0xC0,0xA8,0x01,0x65}; //发送端IP地址 192.168.1.101
	u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; // 因为不知道mac,所以mac为空
	u_char target_ip[4] = {0xC0,0xA8,0x01,0x6F}; // 目的端ip 192.168.1.111;

	if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
	{
		printf("Packet arp request error\n");
		return -1;
	}
	return 0;
}

void main(int argc, char **argv)
{
	pcap_t *fp;
	char errbuf[PCAP_ERRBUF_SIZE];
	u_char packet[ARP_LEN];
	int i;

	pcap_if_t *d = choose_interface();
	if(d == NULL)
	{
		exit(1);
	}
	char *source = d->name;

    /* Open the output device */
	if ( (fp= pcap_open(source,            // name of the device
                        100,                // portion of the packet to capture (only the first 100 bytes)
                        PCAP_OPENFLAG_PROMISCUOUS,  // promiscuous mode
                        1000,               // read timeout
                        NULL,               // authentication on the remote machine
                        errbuf              // error buffer
                        ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
        return;
    }

	Arp arp;
	if(Text1(&arp) == -1)
	{
		return ;
	}

	memcpy(packet, (void*)&arp, ARP_LEN);
    /* Send down the packet */
	if (pcap_sendpacket(fp, packet, ARP_LEN /* size */) != 0)
	{
		fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
		return;
	}

    return;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-29 19:06:10

ARP协议(4)ARP编程的相关文章

ARP协议及ARP欺骗详解

ARP协议及ARP欺骗详解 地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议.主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址:收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源.ARP缓存是个用来储存IP地址和MAC地址的缓冲区,其本质就是一个IP地址-->MAC地址的对应表,表中每一个条目分别记

ARP协议(3)ARP编程--winpcap&amp;vs2012配置

好,之前说了那么多,终于到了,我们可以操刀的时候了. 在对ARP协议编程前,我们必须要能控制网络适配器(网卡),这个部分就是驱动! "我们要编写网卡驱动?",对,但是,至少我们现阶段不需要.网络上有写好的驱动和开发包,我们拿来就可以用.我这里使用的是winpcap的驱动以及开发包,因此我们首先要安装和搭建我们的编程环境: 1.下载winpcap驱动. 如果是安装了wireshark的话,它就自动帮我们装了winpcap驱动.(wireshark是基于winpcap开发的) http:/

ARP协议(2)ARP协议格式详解

一.协议格式 ARP协议的格式如下: 分两大块来讲解: 1.红色框起来的是:以太网的首部,共14字节. 这部分是你不管发送什么以太网协议的数据包,它都是需要的,而且是必须的.各字段的说明: 字段 所占字节数 说明 以太网目的地址 6 要向哪台主机发送信息,主机的MAC地址 以太网源地址 6 信息是从哪台机器发送出来的,主机的MAC地址 帧类型 2 表示这是什么类型的数据包.如果是RAP的话,该值为:0x0806 2.蓝色框起来的部分,这就是ARP协议的格式(请求/应答) 字段 所占字节数 说明

浅析ARP协议及ARP攻击

一. ARP数据包结构 (1)硬件类型:指明发送方想知道的硬件接口类型,以太网的值为1:(2)协议类型:指明发送方提供的高层协议类型:它的值为 0x0800 即表示 IP地址.(3)硬件地址长度和协议长度: 指明硬件地址和高层协议地址的长度,这样ARP报文就可以在任意硬件和任意协议的网络中使用:对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4.(4)op:操作字段用来表示这个报文的类型,ARP请求为1,ARP响应为2,RARP请求为3,RARP响应为4: ARP协议解析过程: 1

ARP协议(5)ARP攻击和防护

一.ARP攻击 我们先来看ARP的功能:ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的进行. ARP的具体实现方式,我在<ARP协议(1)什么是ARP协议>已有说明: Q:这张映射表是如何生成的? A: (1)这张表中,每条记录(非静态)的生存时间一般为20分钟,起始时间从被创建开始算起,一旦过期,将在这张表中删除.(手动删除全部,可以用 arp -d *命令). (2)当A主机要发送信息给B时,A先在ARP高速缓存里查询B的IP是否有对应的MAC地址,

Networking - ARP 协议

ARP 协议概述 ARP(Address Resolution Protocol),即地址解析协议,用于把 IP 地址映射到物理地址.网段上的每台主机都维护着一个被称为 ARP Table 或 ARP Cache 的表格,其中包含着网段上其他主机的 IP 地址与物理地址的对应关系.当主机需要向网段上的其他主机发送数据时,它会查看 ARP Cache 来获得目的的物理地址.ARP 缓存是动态变化的.如果要接收数据的地址当前并不存在于 ARP Cache,主机就会广播一个 ARP 请求帧.ARP 请

【网络】ARP协议

其实在网络传输中,分为不同的层次,然后不同的层分类了不同的协议,我们来简单看一下协议的分类图: 今天我来讲解一下APR协议: 什么是ARP协议: 对于APR协议,我们首先需要了解网络IP的概念,在网络层中,IP是网络层的唯一标识,但是对于我们寻找到网络局域后进行通信的具体主机是哪一台,也就是确定具体的接收方主机,我们需要确定双方的MAC帧,也就是物理地址,物理地址才能够真正确定双方的具体对象,IP是针对于网络层而言的唯一性.所以为了避免发送端不知道接收端的MAC地址,所以就出现了ARP协议. A

在实践中深入理解ARP协议

0.说明 在同一个网络(无特别说明,均指以太网络)中进行通信的主机,必须要拥有目标主机的MAC地址才能够正确地将数据发送给目标主机,那么如何知道目标主机的MAC地址呢?可以通过ARP协议.ARP协议就是用来获取目标IP地址所对应的MAC地址的,也就是说,ARP协议可以动态地在三层IP地址和二层MAC地址之间建立一种映射关系.可以用如下示意图来形象表示其作用: 可以看到上面的图示是把ARP协议划分到网络层,也既是认为它是一个网络层的协议,这是出于它为网络层的IP协议提供服务而考虑的.但实际上,由于

计算机网路之ARP协议初见

今天在做题的时候发现ARP协议不是很懂,于是我去搜了一些资料,学习了一下,这里记录一下自己的总结. 一.为什么会有ARP协议的产生呢? 答:这是因为在直接相连的网络中,两个节点是利用彼此的MAC地址互相传送帧的.但是当网络层数据报交付给源端系统时,该端系统只能获得目的端系统的ip地址,依然不能进行数据的传送,所以需要一个协议来根据已知的ip地址获得对应得MAC地址,这个时候就产生了ARP协议,ARP协议将解析到的目的IP和MAC地址存储在本地的ARP缓冲中(地址映射表),供下次使用.ARP全称是