Linux ARP协议源码详细讲解

合集下载

ARP协议详解ARP报文结构

ARP协议详解ARP报文结构

ARP协议详解ARP报文结构ARP协议详解与ARP报文结构ARP(Address Resolution Protocol,地址解析协议)是一个重要的网络协议,用于将IP地址与MAC地址相互映射。

在局域网中,每个主机都有一个唯一的IP地址和MAC地址,而ARP协议则负责通过目标IP地址获取对应的MAC地址,从而实现数据包的正确传输。

一、ARP工作流程ARP的工作流程可以简单概括为以下几个步骤:1. 发送ARP请求:源主机A在发送数据包时,会先检查目标主机B的IP地址是否与自己在同一局域网中,如果不是,则需要获取目标主机的MAC地址。

A会根据目标主机的IP地址构建一个ARP请求包(ARP Request),该包中包含源主机A的IP地址、MAC地址以及目标主机的IP地址。

然后,A会将ARP请求包广播发送到局域网中的所有主机。

2. 接收ARP请求:局域网中的其他主机收到ARP请求包后会进行筛选,只有与ARP请求包中的目标IP地址相同的主机会继续处理。

3. 发送ARP响应:局域网中的目标主机B收到ARP请求包后会将自己的MAC地址信息封装在一个ARP响应包(ARP Reply)中,并发送给源主机A。

该ARP响应包中包含目标主机B的IP地址、MAC地址以及源主机A的IP地址。

4. 更新ARP缓存表:源主机A收到ARP响应包后会将目标主机B的IP地址与其对应的MAC地址映射关系添加到本地的ARP缓存表中,以备将来使用。

5. 数据传输:当主机A获取到目标主机B的MAC地址后,就可以将待发送的数据包封装在以太网帧中,通过局域网将数据包传输给目标主机B。

二、ARP报文结构ARP报文结构包括以下字段:1. 硬件类型(Hardware Type):占2字节,表示硬件接口类型,例如以太网。

2. 协议类型(Protocol Type):占2字节,表示网络协议类型,例如IPv4或IPv6。

3. 硬件地址长度(Hardware Address Length):占1字节,表示源和目标MAC地址的长度,通常为6(以太网中的MAC地址长度)。

Linux下查看arp静态绑定地址详解

Linux下查看arp静态绑定地址详解

Linux下查看arp静态绑定地址详解首先,做两个对比试验:root@janbe root]# arp -a(192.168.8.241) at 00:15:58:A2:13: D0 [ether] on eth0(192.168.8.1) at 00:15:C5:E1: D1:58 [ether] on eth0[root@janbe bin]# arp -s 192.168.8.1 00:15:C5:E1: D1:58[root@janbe bin]# arp -a(192.168.8.241) at 00:15:58:A2:13: D0 [ether] on eth0(192.168.8.1) at 00:15:C5:E1: D1:58 [ether] PERM on eth0发现没有?多了一个PERM!!或者[root@janbe bin]# cat /proc/net/arpIP address HW type Flags HWaddress Mask Device192.168.8.241 0x1 0x2 00:15:58:A2:13:D0 * eth0192.168.8.1 0x1 0x6 00:15:C5:E1: D1:58 * eth0[root@janbe bin]# arp -s 192.168.8.241 00:15:58:A2:13: D0[root@janbe bin]# cat /proc/net/arpIP address HW type Flags HWaddress Mask Device192.168.8.241 0x1 0x6 00:15:58:A2:13:D0 * eth0192.168.8.1 0x1 0x6 00:15:C5:E1:D1:58 * eth0发现没有?Flags改变了!所以我们可以用两种方法找到arp的静态绑定地址:#arp -a | grep PERM或者#cat /proc/net/arp | grep 0x6但建议用后者比较快。

ARP协议的C语言实现源代码

ARP协议的C语言实现源代码
target = *(argv+1); if (inet_aton(target, &dst) != 1) {
struct hostent *hp; hp = gethostbyname2(target, AF_INET); printf("\ntarget = %s \n", target ); if (!hp) {
printf("Interface \"%s\" is down\n", if_dev); exit(2); } if (ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) {
printf("Interface \"%s\" is not ARPable\n", if_dev); exit(2); } return ifindex; } // check_device() int socket_init() {
fprintf(stderr, "arping: unknown iface %s\n", if_dev); exit(2); } ifindex = ifr.ifr_ifindex; if (ioctl(ss, SIOCGIFFLAGS, (char*)&ifr)) { perror("ioctl(SIOC); } if (!(ifr.ifr_flags&IFF_UP)) {
perror("bind"); exit(2); } int alen = sizeof(me); if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { perror("getsockname"); exit(2); } if (me.sll_halen == 0) { printf("Interface \"%s\" is not ARPable (no ll address)\n", device); exit(2); } he = me; memset(he.sll_addr, -1, he.sll_halen); // set dmac addr FF:FF:FF:FF:FF:FF return s; } int create_pkt(unsigned char * buf, struct in_addr src, struct in_addr dst, struct sockaddr_ll * FROM, struct sockaddr_ll * TO) { struct arphdr *ah = (struct arphdr*) buf; unsigned char *p = (unsigned char *)(ah+1); ah->ar_hrd = htons(FROM->sll_hatype); if (ah->ar_hrd == htons(ARPHRD_FDDI)) ah->ar_hrd = htons(ARPHRD_ETHER); ah->ar_pro = htons(ETH_P_IP); ah->ar_hln = FROM->sll_halen; ah->ar_pln = 4; ah->ar_op = htons(ARPOP_REQUEST); memcpy(p, &FROM->sll_addr, ah->ar_hln); p+=FROM->sll_halen; memcpy(p, &src, 4); p+=4; memcpy(p, &TO->sll_addr, ah->ar_hln); p+=ah->ar_hln; memcpy(p, &dst, 4); p+=4;

linux arp 工作原理

linux arp 工作原理

linux arp 工作原理Linux ARP(Address Resolution Protocol)是一种网络协议,用于将IP地址转换为MAC地址。

在本文中,我们将探讨Linux ARP的工作原理。

ARP的目的是将IP地址与MAC地址相互映射,以便在网络中进行通信。

在实际的网络通信中,数据包是通过MAC地址进行传输的,而IP地址则用于标识不同的主机。

因此,需要一种机制来将IP地址转换为MAC地址,这就是ARP的作用。

当一台主机需要与另一台主机进行通信时,它首先会检查自己的ARP缓存表(ARP cache)中是否有对应的IP地址和MAC地址的映射。

如果有,它就可以直接使用该MAC地址发送数据包。

如果没有,它就需要发送一个ARP请求广播以寻找目标主机的MAC地址。

ARP请求广播是一种特殊的数据包,其中包含了发送方的IP地址和MAC地址,以及目标IP地址。

当目标主机收到这个广播消息后,它会检查自己的IP地址是否与请求中的目标IP地址匹配。

如果匹配,它就会向发送方发送一个ARP响应,其中包含了自己的IP地址和MAC地址。

当发送方收到ARP响应后,它会将目标主机的IP地址和MAC地址添加到自己的ARP缓存表中,并使用该MAC地址发送数据包。

这样,下次发送方需要与目标主机通信时,就可以直接使用已知的MAC地址,而无需发送ARP请求。

需要注意的是,ARP是一个局域网协议,只适用于同一个子网内的通信。

如果目标主机与发送方不在同一个子网内,发送方在发送数据包之前还需要获取网关的MAC地址。

这时,发送方会向网关发送ARP请求,以获取网关的MAC地址。

ARP缓存表是动态维护的,会随着时间的推移而更新。

当一条记录在一定时间内没有被使用时,系统会将其从ARP缓存表中删除。

这是为了保持ARP缓存表的有效性,并防止过时的映射导致通信错误。

总结一下,Linux ARP工作原理可以概括为以下几个步骤:1. 发送方检查ARP缓存表,如果有目标主机的MAC地址映射,则直接发送数据包。

linux struct arphdr结构

linux struct arphdr结构

linux struct arphdr结构
struct arphdr是Linux中用于定义ARP报文头部的结构体。

ARP(Address Resolution Protocol)是一种网络协议,用于将IP地址映射到MAC地址。

struct arphdr结构体定义了ARP报文的格式,包括以下字段:
- ar_hrd:硬件地址类型,指定ARP使用的硬件类型,如Ethernet。

- ar_pro:协议地址类型,指定ARP使用的协议类型,如IPv4。

- ar_hln:硬件地址长度,表示硬件地址的字节数。

- ar_pln:协议地址长度,表示协议地址的字节数。

- ar_op:操作码,指定ARP报文的类型,如ARP请求和ARP响应。

通过使用struct arphdr,可以轻松地构建和解析ARP报文。

例如,在发送ARP
请求时,可以设置ar_op字段为ARP请求的操作码,并设置其他字段来指示发送
者的硬件和协议地址,以及目标地址。

同样地,在接收ARP报文时,可以使用struct arphdr来解析报文头部,从中提取所需的信息。

结构体的使用让开发人员可以在Linux中处理ARP报文变得更加简单和高效。

通过了解struct arphdr的定义和使用方法,开发人员可以更好地理解和操作ARP协议,在网络编程中起到关键作用。

总之,通过使用Linux中的struct arphdr结构体,开发人员能够方便地处理
ARP报文,实现IP地址到MAC地址的映射。

这对于网络编程和网络管理非常重要,有助于提高网络通信的效率和可靠性。

linuxarp命令常用参数详解

linuxarp命令常用参数详解

linuxarp命令常⽤参数详解linux arp 命令常⽤参数详解显⽰和修改地址解析协议(ARP)使⽤的“IP 到物理”地址转换表。

ARP -s inet_addr eth_addr [if_addr]ARP -d inet_addr [if_addr]ARP -a [inet_addr] [-N if_addr] [-v]-a 通过询问当前协议数据,显⽰当前 ARP 项。

如果指定 inet_addr,则只显⽰指定计算机的 IP 地址和物理地址。

如果不⽌⼀个⽹络接⼝使⽤ ARP,则显⽰每个 ARP 表的项。

-g 与 -a 相同。

-v 在详细模式下显⽰当前 ARP 项。

所有⽆效项和环回接⼝上的项都将显⽰。

inet_addr 指定 Internet 地址。

-N if_addr 显⽰ if_addr 指定的⽹络接⼝的 ARP 项。

-d 删除 inet_addr 指定的主机。

inet_addr 可以是通配符 *,以删除所有主机。

-s 添加主机并且将 Internet 地址 inet_addr与物理地址 eth_addr 相关联。

物理地址是⽤连字符分隔的 6 个⼗六进制字节。

该项是永久的。

eth_addr 指定物理地址。

if_addr 如果存在,此项指定地址转换表应修改的接⼝的 Internet 地址。

如果不存在,则使⽤第⼀个适⽤的接⼝。

⽰例:添加静态项。

这个很有⽤,特别是局域⽹中中了arp病毒以后> arp -s 123.253.68.209 00:19:56:6F:87:D2> arp -a .... 显⽰ ARP 表。

但是arp -s 设置的静态项在⽤户登出之后或重起之后会失效,如果想要任何时候都不失效,可以将ip和mac的对应关系写⼊arp命令默认的配置⽂件/etc/ethers中例如:引⽤root@ubuntu:/# vi /etc/ethers211.144.68.254 00:12:D9:32:BF:44写⼊之后重起以下⽹络就好了。

linuxarp命令的功能及使用方法

linuxarp命令的功能及使用方法

linuxarp命令的功能及使用方法Arp命令(Address Resolution Protocol)是一个用于在局域网内解决IPv4地址与MAC(物理)地址之间映射关系的网络协议。

它主要用于根据目标IPv4地址查询目标MAC地址,以实现数据包的传输。

在Linux系统中,arp命令用于管理和操作本地ARP缓存表。

本文将详细介绍Linux中arp命令的功能及使用方法。

一、功能介绍:1. 查看ARP缓存表-arp -a使用arp -a命令可以查看本地ARP缓存表的信息,包括IP地址、MAC地址、接口类型等。

2. 添加静态ARP表项-arp -s通过arp -s命令可以添加或修改静态ARP表项,声明一些IPv4地址对应的MAC地址,静态ARP表项不会自动过期。

3. 删除ARP表项-arp -d通过arp -d命令可以删除指定的ARP表项,将其从本地ARP缓存表中移除。

4. 清空ARP缓存表-arp -c使用arp -c命令可以清空本地ARP缓存表,删除所有的ARP表项。

二、使用方法:1.查看ARP缓存表输入命令:arp -a示例输出:```(192.168.1.1) at 00:11:22:33:44:55 [ether] on eth0(192.168.1.2) at 00:11:22:33:44:56 [ether] on eth0(192.168.1.3) at 00:11:22:33:44:57 [ether] on eth0...```2.添加静态ARP表项输入命令:arp -s IP地址 MAC地址示例命令:arp -s 192.168.1.100 00:11:22:33:44:66添加了一个静态的ARP表项,将192.168.1.100对应的MAC地址设置为00:11:22:33:44:663.删除ARP表项输入命令:arp -d IP地址示例命令:arp -d 192.168.1.100删除了ARP缓存表中的192.168.1.100对应的条目。

Linux实现的ARP缓存老化时间原理解析

Linux实现的ARP缓存老化时间原理解析

Linux实现的ARP缓存老化时间原理解析一.问题众所周知,ARP是一个链路层的地址解析协议,它以IP地址为键值,查询保有该IP地址主机的MAC地址。

协议的详情就不详述了,你可以看RFC,也可以看教科书。

这里写这么一篇文章,主要是为了做一点记录,同时也为同学们提供一点思路。

具体呢,我遇到过两个问题:1.使用keepalived进行热备份的系统需要一个虚拟的IP地址,然而该虚拟IP地址到底属于哪台机器是根据热备群的主备来决定的,因此主机器在获得该虚拟IP的时候,必须要广播一个免费的arp,起初人们认为这没有必要,理由是不这么做,热备群也工作的很好,然而事实证明,这是必须的;2.ARP缓存表项都有一个老化时间,然而在linux系统中却没有给出具体如何来设置这个老化时间。

那么到底怎么设置这个老化时间呢?二.解答问题前的说明ARP协议的规范只是阐述了地址解析的细节,然而并没有规定协议栈的实现如何去维护ARP缓存。

ARP缓存需要有一个到期时间,这是必要的,因为ARP缓存并不维护映射的状态,也不进行认证,因此协议本身不能保证这种映射永远都是正确的,它只能保证该映射在得到arp应答之后的一定时间内是有效的。

这也给了ARP欺骗以可乘之机,不过本文不讨论这种欺骗。

像Cisco或者基于VRP的华为设备都有明确的配置来配置arp缓存的到期时间,然而Linux系统中却没有这样的配置,起码可以说没有这样的直接配置。

Linux用户都知道如果需要配置什么系统行为,那么使用sysctl工具配置procfs下的sys接口是一个方法,然而当我们google了好久,终于发现关于ARP的配置处在/proc/sys/net/ipv4/neigh/ethX的时候,我们最终又迷茫于该目录下的N多文件,即使去查询Linux内核的Documents也不能清晰的明了这些文件的具体含义。

对于Linux这样的成熟系统,一定有办法来配置ARP缓存的到期时间,但是具体到操作上,到底怎么配置呢?这还得从Linux实现的ARP状态机说起。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux ARP协议源码详细讲解arp_tbl是一个类型为struct neigh_table的全局变量,它是一个ARP的缓存表,也称为邻居表。

协议栈通过ARP协议获取到的网络上邻居主机的IP地址与MAC地址的对应关系都会保存在这个表中,以备下次与邻居通讯时使用,同时,ARP模块自身也会提供一套相应的机制来更新和维护这个邻居表。

下面逐个分析arp_tbl中的重要成员数据与函数。

entry_size,key_len,kmem_cachep。

entry_size是一个入口的大小,也就是arp_tbl中一个邻居的大小,邻居用struct neighbour结构体表示,该结构体的最后一个成员是u8 primary_key[0],用于存放IP地址,作为这个邻居的哈希主键。

所以entry_size 的大小就是sizeof(struct neighbour) + 4,因为是用IP地址作主键,所以key_len就是4。

kmem_cachep是一个后备高速缓存,创建一个邻居需要的内存从这个后备高速缓存中去取。

hash_buckets,hash_mask,entries,hash。

hash_buckets是一个哈希数组,里面存放了arp_tbl当前维护的所有的邻居,hash_mask是哈希数组大小的掩码,其初始值为1,所以 hash_buckets的初始大小为2(0到hash_mask的空间范围)。

entries是整个arp_tbl中邻居的数量,当entries大于 hash_mask+1的时候,hash_buckets增长为原来的两部。

成员hash是一个哈希函数指针,用于计算哈希值。

phash_buckets,PNEIGH_HASHMASK。

这是用于代理ARP的邻居哈希表,PNEIGH_HASHMASK固定为0xF,所以phash_buckets固定有16项,其它与hash_buckets相同。

id。

id作为这个邻居表的一个名称,是一个字符串信息,内核协议栈的arp_tbl 的id是arp_cache。

gc_interval,gc_thresh1,gc_thresh2,gc_thresh3。

gc_thresh3是arp_tbl中允许拥有的邻居数量的上限,一旦超过这个上限,并且表中没有可以清理掉的垃圾邻居,那么就无法创建新的邻居,这个值缺省被置为1024。

gc_thresh2是第二个阀值,如果表中的邻居数量超过这个阀值,并且在需要创建新的邻居时,发现已经超过5秒时间表没有被刷新过,则必须立即刷新arp_tbl表,进行强制垃圾回收,这个值缺省被置为512。

gc_thresh1的用途暂时还没有发现,它缺省被置为128。

gc_interval应该是常规的垃圾回收间隔时间,被缺省置为30秒,但目前在源代码中似乎没有看到它的应用。

强制垃圾收集的工作即是把引用计数为 1,且状态中没有NUD_PERMANENT的邻居全部从arp_tbl表中删除。

gc_timer。

这是一个常规垃圾回收的定时器,其定时处理函数是neigh_periodic_timer。

该定时器超时后,处理函数处理hash_buckets表中的一项,下次超时后,再处理下一项,这里的垃圾回收比强制垃圾回收条件要宽松得多,如果邻居的状态为NUD_PERMANENT或 NUD_IN_TIMER(该邻居正在解析中),则不能回收。

当邻居的引用计数为1时,并且邻居状态为NUD_FAILED(解析失败)或者该邻居距最近一次被使用时间已超过参数表中gc_staletime的值(缺省为60秒),则可以作为垃圾回收。

回收完毕后,要设置下一次进行回收的时间(gc_timer的超时时间),下次回收时间为参数表中base_reachable_time的值(缺省设为30秒)的一半,再除以 hash_buckets哈希表中的项数。

也就是,基本上15秒左右会把整个arp_tbl缓存表进行一次垃圾回收。

proxy_timer,proxy_queue,proxy_redo。

proxy_timer是一个关于代理ARP的定时器,proxy_queue是一个待处理的代理ARP数据包的队列,每次定时器超时,处理函数 neigh_proxy_process依次检查队列中每一个代理ARP数据包(struct sk_buff),对于超时,且满足相关条件的,调用proxy_redo进行处理。

有关代理ARP,将专门分析讲述,这里暂时略过。

constructor。

这是一个邻居的初始化函数指针,每次创建出一个邻居后,需要马上调用这个函数对新创建的邻居进行一些初始化操作。

邻居创建完,已经被赋于一个IP地址(邻居结构体的primary_key成员),该函数首先根据这个IP地址来确定其地址类型,然后为邻居选择相应的操作函数集(初始化邻居结构体的一些成员,在讲到邻居结构体内容时再进行分析)。

pconstructor,pdestructor。

这是代理ARP的邻居的构建和析构函数指针,在IPv4模块中,未提供这两个函数,所以它们的指针值为空。

parms。

这是一个结构体struct neigh_parms的链表,系统中每个网络设备接口对应链表中一个节点,表示该设备接口上的邻居的一些传输参数。

同时,链表中还有一个缺省的项。

last_rand,hash_rand这两个成员其实没有联系,hash_rand是用于邻居哈希表hash_buckets的一个随机数,last_rand用于记录一个时间,即上次为 parms链表中每个节点生成reachable_time的时间,reachable_time是需要被定时刷新的。

stats。

记录arp_tbl被操作次数的一些统计数据。

结构体struct neigh_table是一个哈希表,用于描述物理上互相连接的机器的信息。

ARP缓存myarp_tbl就是这样的一个结构。

在分析ARP相关的初始化之前,我们先来看一下这个结构体:truct neigh_table{struct neigh_table *next;int family;int entry_size;int key_len;__u32 (*hash)(const void *pkey, const struct net_device *);int (*constructor)(struct neighbour *);int (*pconstructor)(struct pneigh_entry *);void (*pdestructor)(struct pneigh_entry *);void (*proxy_redo)(struct sk_buff *skb);char *id;struct neigh_parms parms;/* HACK. gc_* shoul follow parms without a gap! */int gc_interval;int gc_thresh1;int gc_thresh2;int gc_thresh3;unsigned long last_flush;struct timer_list gc_timer;struct timer_list proxy_timer;struct sk_buff_head proxy_queue;atomic_t entries;rwlock_t lock;unsigned long last_rand;kmem_cache_t *kmem_cachep; struct neigh_statistics *stats; struct neighbour **hash_buckets; unsigned int hash_mask;__u32 hash_rnd;unsigned int hash_chain_gc;struct pneigh_entry **phash_buckets;#ifdef CONFIG_PROC_FSstruct proc_dir_entry *pde;#endif};entry_size是一个入口的长度,一个入口代表一个neighbour的信息,hash_buckets即为存放所有邻居的一个哈希数组,每一项对应一条neighbour链表。

struct neighbour用于代表一个neighbour,包含了其信息,下面是其重要的一些成员:dev代表与这个邻居相连的网络设备;nud_state代表邻居的状态(未完成,无法访问,过时,失败);ha表示邻居的mac地址;hh是以太网包的头部缓存;arp_queue是等待这个邻居的硬件地址的IP包队列;ops是对该neighbour节点操作的一套函数;primary_key是哈希表的主键,一般为IP地址。

key_len是哈希表主键的长度,一般IP地址长度为4。

几个函数分别为哈希函数,构造和析构函数。

parms是ARP缓存的一些参数,包括ARP包传输时间,重发时间,队列长度和代理队列长度等等。

ARP缓存有一个回收机制(garbage collection),上面以gc_开头的参数用来设置回收的频率和阀值等等。

stats是一些关于邻居的统计信息。

ARP初始化的第一个步是初始化ARP缓存myarp_tbl,并把它加到全局链表neigh_tables的表头,其实,系统中所有的neigh_table都放在这个表中。

ptype_base是一个有16项的哈希数组,每种协议包类型都注册在这个数组中。

arp包,其类型是ETH_P_ARP,其接收函数是 myarp_rcv。

有了这个注册信息,当设备上收到一个网络包(packet)的时候,会分配一个sk_buff(skb),将数据拷贝进这个缓冲区,然后调用netif_rx把skb放入等待队列(input_pkt_queue)中,并且产生一个软中断。

当系统处理这个软中断的时候,会调用 net_rx_action,它根据网络包的类型,调用相应的接收函数来处理。

如果是ARP包,则调用myarp_rcv。

ARP缓存myarp_tbl是用于描述物理上相互连接的机器的信息的一个哈希表,关于这个缓存,我们前面作过分析。

现在我们来看看,当主机收到一个需要本地接收的ARP请求时,如何向ARP缓存中更新一个ARP信息。

当网络设备收到一个ARP数据包后,最终会调用到协议栈中的myarp_process处理函数,这个函数的处理会涉及到路由表的查询和更新。

但我们现在的my_inet模块还没有真正完成路由表的初始化,所以略过其中很多细节,只关注ARP缓存的更新与查询。

myarp_process通过调用__neigh_lookup函数更新ARP缓存,下面是该函数的定义:static inline struct neighbour * __neigh_lookup(struct neigh_table *tbl,const void *pkey,struct net_device *dev,int creat)参数tbl是ARP缓存哈希表,传入全局变量myarp_tbl。

相关文档
最新文档