探究linux下c语言与ARP协议的实现 (linux c arp)
探究Linux下C语言与ARP协议的实现
随着计算机网络的迅猛发展,网络通信协议也越来越成熟和复杂,ARP(Address Resolution Protocol)协议是用于将IP地址转换为物理地址的一种网络协议。在Linux系统下,ARP协议的实现是由C语言编写的。本文将探究Linux下C语言与ARP协议的实现。
一、ARP协议的概述
ARP协议是指Address Resolution Protocol,即地址解析协议,它在互联网协议(IP)中被用来将IPv4地址转换成物理硬件地址,例如MAC地址。通俗的理解,ARP协议实现了IP地址到MAC地址的映射,当我们想要与其他设备通信时,首先需要知道目标设备的MAC地址,而ARP协议就是用来完成这个任务的。
当一个网络设备(网卡、路由器、交换机等)需要发送网络数据包时,它会尝试去获取目标IP地址对应的MAC地址,步骤如下:
1. 在ARP缓存中查找对应的IP地址的MAC地址,如果存在,则直接发送数据包到目标设备的MAC地址。
2. 如果ARP缓存中不存在对应的MAC地址,则网卡需要发送一个ARP请求数据包广播到整个网络中,请求目标设备回应自己的MAC地址。广播的数据包的源MAC地址为发送方的MAC地址,目标MAC地址为广播地址FF:FF:FF:FF:FF:FF,目标IP地址为目标设备的IP地址,发送方的IP地址为发送方IP地址。
3. 目标设备接收到ARP请求数据包后,如果发现请求中目标IP与自己的IP地址相同,则回复一个ARP应答数据包,表明自己的MAC地址是什么,此时源设备可以获取到目标设备的MAC地址,并在以后的网络通信中使用该地址。
二、 Linux C语言下的ARP实现
在Linux下,ARP协议的实现主要由C语言编写。下面将介绍Linux C语言下ARP协议实现的主要代码框架。
1. ARP协议数据结构
在Linux中,ARP请求数据包与应答数据包的结构是一致的。下面是ARP数据包的数据结构定义。
“`c
struct arphdr {
__be16 ar_hrd; //硬件地址类型
__be16 ar_pro; //协议地址类型
unsigned char ar_hln; //硬件地址长度
unsigned char ar_pln; //协议地址长度
__be16 ar_op; //ARP操作码
unsigned char ar_sha[ETH_ALEN]; //源MAC地址
__be32 ar_sip; //源IP地址
unsigned char ar_tha[ETH_ALEN]; //目标MAC地址
__be32 ar_tip; //目标IP地址
};
“`
其中,ar_hrd表示硬件地址类型,ar_pro表示协议地址类型,ar_hln表示硬件地址长度,ar_pln表示协议地址长度,ar_op表示ARP操作码,ar_sha表示源MAC地址,ar_sip表示源IP地址,ar_tha表示目标MAC地址,ar_tip表示目标IP地址。
2. ARP协议接口程序
ARP协议的实现主要由arp.c程序实现,下面是该程序的主要代码框架。
“`c
#include
#include
#include
#include
void arp_rcv(struct sk_buff *skb) {
//接收ARP数据包并进行处理
}
int arp_send(unsigned int type, struct net_device *dev,
unsigned long dest_ip, const unsigned char *dest_hw,
unsigned long src_ip, const unsigned char *src_hw,
const unsigned char *target_hw) {
//发送ARP数据包
}
void arp_create(struct net_device *dev) {
//创建ARP缓存
}
void arp_destroy(struct net_device *dev) {
//销毁ARP缓存
}
void arp_timer(unsigned long data) {
//处理ARP缓存中的超时数据
}
static struct neigh_parms * arp_parms_alloc(struct net_device *dev) {
//分配neigh_parms结构体
}
static void arp_parms_free(struct neigh_parms *parms) {
//释放neigh_parms结构体
}
static struct neigh_parms_template arp_parms_template = {
.parmsize = sizeof(struct arp_parms),
.neigh_priv_size = sizeof(struct arp_neigh),
.neigh_setup = arp_neigh_setup,
.neigh_cleanup = arp_neigh_cleanup,
};
void __init arp_init(void) {
//注册ARP协议到内核
}
“`
其中,arp_rcv函数用于接收ARP数据包,并进行处理;arp_send函数用于发送ARP数据包;arp_create函数用于创建ARP缓存;arp_destroy函数用于销毁ARP缓存;arp_timer函数用于处理ARP缓存中的超时数据。此外,arp_parms_alloc函数和arp_parms_free函数用于分配和释放neigh_parms结构体,而arp_parms_template结构体则定义了ARP协议相关的参数模板。
3. ARP协议的实现流程
ARP协议的实现流程主要包含以下几个步骤。
1. 接收ARP数据包
当一个ARP数据包到达时,首先需要通过arp_rcv函数接收数据包。
“`c
void arp_rcv(struct sk_buff *skb) {
struct arphdr *arp;
struct neighbour *neigh;
//检查数据包的长度是否正确
if (/* !数据包长度正确 */) {
kfree_skb(skb);
return;
}
//获取ARP协议头
arp = arp_hdr(skb);
//分配缓存结构体
neigh = neighbour_alloc(&arp_tbl, &arp->saddr, arp->ar_hln, 0, skb->dev);
if (neigh) {
//缓存数据包
neighbour_update(neigh, skb);
neighbour_release(neigh);
}
//释放缓存
kfree_skb(skb);
}
“`
在接收到数据包后,首先需要检查数据包的长度是否正确,然后通过arp_hdr函数获取ARP协议头。接下来需要分配缓存结构体,这里使用neighbour_alloc函数完成,该函数可以分配一个neighbour结构体并将其插入到neighbour表中。当缓存数据包后,使用neighbour_update函数更新缓存,并通过neighbour_release函数将缓存的neigh结构释放。最后将skb数据包指针释放。
2. 发送ARP数据包
当需要发送ARP数据包时,需要调用arp_send函数。
“`c
int arp_send(unsigned int type, struct net_device *dev,
unsigned long dest_ip, const unsigned char *dest_hw,
unsigned long src_ip, const unsigned char *src_hw,
const unsigned char *target_hw) {
struct sk_buff *skb;
struct arphdr *arp;
//分配skb缓存结构体
skb = alloc_skb(/* 指定缓存长度 */, GFP_ATOMIC);
if (!skb) {
return -ENOMEM;
}
//填充ARP头部
arp = (struct arphdr *) skb_put(skb, sizeof(struct arphdr));
//设置各个字段值
arp->ar_hrd = htons(ARPHRD_ETHER);
arp->ar_pro = htons(ETH_P_IP);
arp->ar_hln = ETH_ALEN;
arp->ar_pln = 4;
arp->ar_op = htons(type);
memcpy(arp->ar_sha, src_hw, ETH_ALEN);
arp->ar_sip = htonl(src_ip);
memset(arp->ar_tha, 0, ETH_ALEN);
arp->ar_tip= htonl(dest_ip);
if (target_hw) {
memcpy(arp->ar_tha, target_hw, ETH_ALEN);
}
//填充数据链路头
//调用dev_hard_start_xmit函数发送数据包
//释放skb缓存结构体
return 0;
}
“`
发送ARP数据包时,首先需要分配一个skb缓存结构体,然后填充ARP头部,设置各个字段值。最后将数据链路头填充,调用dev_hard_start_xmit函数发送数据包,发送完成后释放skb缓存结构体。
3. 创建和销毁ARP缓存
在ARP协议的实现中,需要创建一个缓存表用于存储ARP请求的响应数据。当缓存中的数据超时后,需要将其从缓存表中释放。
“`c
void arp_create(struct net_device *dev) {
//创建ARP缓存
}
void arp_destroy(struct net_device *dev) {
//销毁ARP缓存
}
“`
这里的arp_create和arp_destroy函数用于创建和销毁ARP缓存表。
4. ARP定时器
在ARP协议的实现中,由于网络环境可能会发生变化,ARP缓存中的数据可能会失效。因此,需要使用ARP定时器定期检查ARP缓存中的数据是否已经超时,如果已经超时,则需要将其释放。
“`c
void arp_timer(unsigned long data) {
//处理ARP缓存中的超时数据
}
“`
在定时器中,需要遍历缓存表,检查缓存中每个元素的时间戳是否已经超时,如果已经超时,则需要将其从缓存表中释放。
三、结论