Linux内核邻接子系统(arp协议)的工作原理(二)
ARP协议(工作在三层)
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的,局域网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存;由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。相关协议有RARP、代理ARP。NDP用于在IPv6中代替地址解析协议。
代理ARP(proxy ARP):对于没有配置缺省网关的计算机要和其他网络中的计算机实现通信,网关收到源计算机的 ARP 请求会使用自己的 MAC 地址与目标计算机的 IP地址对源计算机进行应答。**代理ARP就是将一个主机作为对另一个主机ARP进行应答。它能使得在不影响路由表的情况下添加一个新的Router,使得子网对该主机来说变得更透明化。**同时也会带来巨大的风险,除了ARP欺骗,和某个网段内的ARP增加,最重要的就是无法对网络拓扑进行网络概括。代理ARP的使用一般是使用在没有配置默认网关和路由策略的网络上的。
ARP协议是在RFC 826中定义的。在以太网中,硬件地址称为MAC地址,长48位。MAC地址必须是独一无二的,但必须考虑这样的情形,即可能会遇到并非独一无二的MAC地址。导致这种情形的一种常见原因是,在大多数网络接口上,系统管理员都可使用诸如ifconfig或ip等用户空间工具配置MAC地址。 发送IPv4数据包时,目标IPv4地址是已知的,但需要创建以太网报头,其中包含目标MAC地址。根据给定IPv4地址确定MAC地址的工作由ARP协议完成,稍后你讲看到这一点。如果MAC地址未知,就以广播方式发送ARP请求,其中包含已知的IPv4地址。如果有主机配置了这个IPv4地址,它将使用单播ARP响应进行应答。ARP表( arp_tbl)是一个neigh_table结构实例。ARP报头用结构arphdr表示。
arphdr include\linux\if_arp.h
ar_hrd是硬件地址类型,对于以太网来说,其为0x01。关于可在ARP报头中使用的硬件地址标识符完整列表,请参阅include/uapi/linux/if_arp.h中的ARPHRD_XXX定义。 ar_pro是协议ID,对于IPv4来说,其为0x80。关于可使用的协议ID完整列表,请参阅include/uapi/linux/if_ether.h中的ETH_P_XXX定义。 ar_hln是硬件地址长度,单位为字节。对于以太网地址来说,其为6字节。 ar_pln是协议地址长度,单位为字节。对于IPv4地址来说,其为4字节。 ar_op是操作码。ARP请求表示为ARPOP_REQUEST,ARP应答表示为ARPOP_REPLY。 紧跟在ar_op后面的是发送方的硬件(MAC)地址和IPv4地址,以及目标硬件(MAC)地址和IPv4地址。这些地址并非ARP报头(结构arphdr )的组成部分。在方法arp_process()中,通过读取ARP报头相应的偏移量来提取它们。在讨论方法arp_process()时,你将看到这一点。下图显示了ARP以太网数据包的ARP报头。

ARP包是前面是MAC首部 —— 目地MAC地址(8字节)源MAC地址(8字节)类型(2字节)
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)


ARP 解析 MAC 地址
首先,每台主机都会在自己的ARP缓冲区(ARP Cache)中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。
当源主机需要将一个数据包要发送到目的主机时,会首先检查自己 ARP列表中是否存在该 IP地址对应的MAC地址,如果有﹐就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。
网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;
源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
发送 ARP报文 ARP 发送请求
请求是在哪里发送的呢?最常见的场景是在传输路径中。在离开网络层(L3)进人数据链路层(L2)之前。在方法ip_finish_output2()中,首先调用方法_ipv4_neigh_lookup_noref(),在ARP表中查找下一跳IPv4地址。如果没有找到匹配的邻居条目,就调用方法_neigh_create()来创建一个。
ARP发送报文
arp_solicit函数,邻居子系统调用solicit函数指针 (neigh_ops) 发送solicitation请求,在arp指针中这个函数指针被初始化为arp_solicit函数。
最终调用方法arp_send()来发送ARP请求。我们注意到最后一个参数(target_hw)为NULL,因为还不知道目标硬件(MAC)地址。在调用arp_send()时,如果参数target_hw为NULL,将以广播方式发送ARP请求。
接收 ARP报文
arp_rcv函数被注册到内核中,当有ARP协议报文调用arp_rcv处理。 某些情况下收到一个ARP报文可能导致发出一个ARP报文,这些情况是:
配置了网桥,网桥只是转发报文到其他接口。
邻居子系统对请求报文做出应答。
在方法arp_process()中,只处理ARP报文请求和响应(回复)
对于ARP请求,将使用方法ip_route_input_noref()执行路由选择子系统查找。 如果ARP数据包是发送给当前主机的(路由选择条目的rt_type为RTN_LOCAL),就接着检查一些条件(这将稍后介绍)。如果这些检查都通过了,就使用方法arp_send()发回ARP应答。 如果ARP数据包不是发送给当前主机但需要进行转发的(路由选择条目的rt_type为RTN_UNICAST),也需要检查一些条件(也将在稍后介绍)。如果这些条件都满足,就调用方法pneigh_lookup()在代理ARP表中进行查找。 比如arp_process() 首先验证ARP报文头和设备是否使能ARP功能。 arp_process函数只处理ARPOP_REPLY和ARPOP_REQUEST报文类型。
主机还不知道默认网关的MAC地址,它会发起ARP的请求 主机生成一个包含目的地址为网关路由器 IP 地址(DHCP)的 ARP 查询报文,将该 ARP 查询报文放入一个具有广播目的地址(的以太网帧中,并向交换机发送该以太网帧,交换机将该帧转发给所有的连接设备,包括网关路由器。 默认网关把它自己的MAC地址作为应答回来 Host1开始封装它的数据了,目的为默认网关的MAC地址 Host1发出的数据通过MAC寻址送到了默认网关 默认网关收到数据之后(解封装、提取出目的IP、查表)然后转发出去(重新封装,源/目的MAC地址都发送了转换),最后就把这个数据发往Host4所在的EE网络(当然有可能也不知道Host4的MAC地址,这个时候网关一样会发送ARP请求)
