按照之前的计划,今天开始学习RFC 826文档,在文章开始前,先了解什么是RFC(我前面提过)
Request For Comments(RFC),是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。基本的互联网通信协议都有在RFC文件内详细说明。RFC文件还额外加入许多在标准内的论题,例如对于互联网新开发的协议及发展中所有的记录。因此几乎所有的互联网标准都有收录在RFC文件之中
RFC(Request For Comments)意即“请求评论”,包含了关于Internet的几乎所有重要的文字资料。如果你想成为网络方面的专家,那么RFC无疑是最重要也是最经常需要用到的资料之一,所以RFC享有网络知识圣经之美誉
标题
RFC 826文档是定义哪个协议的内容,我们从文档标题中一目了然
An Ethernet Address Resolution Protocol,以太网地址解析协议,又称为ARP协议
ARP协议的作用是什么呢,标题中-- or --的后面又做了进一步的解释
Converting Network Protocol Addresses to 48.bit Ethernet Address for Transmission on Ethernet Hardware,将网络协议地址转换为48位的以太网地址,目的是以便在以太网硬件上传输
解释下,这里的网络协议地址指的是网络层地址,也就是IPv4地址,48位的以太网地址,指的是硬件地址,也就是MAC地址,从这里我们可以知道MAC地址是48位,6个字节
所以,ARP协议的作用是通过IP地址获取MAC地址,以便报文能够完整封装,只有完整的以太网报文才可以从网卡上发出去
为什么这里的IP地址单独指出是IPv4地址?
因为只有IPv4模块使用ARP协议解析硬件地址,IPv6协议有自己的地址解析协议
ARP报文格式
ARP协议报文格式如下:
ARP报文由两部分组成
- 二层首部
- 48位以太网目的地址,目的MAC地址
- 48位以太网发送地址,源MAC地址
- 16位协议类型,表明二层以上的协议类型,以便把data交给正确的协议模块处理
- 数据
- 16位硬件地址空间,也称为硬件地址类型(比如,以太网,w分组无线网)
- 16位协议地址空间,也称为协议地址类型
- 8位硬件地址长度
- 8位协议地址长度
- 16位opcode,也称为操作类型(REQUEST or REPLY)
- n位发送方硬件地址
- m位发送方协议地址
- n位接收方硬件地址
- m位接收方协议地址
报文生成
当数据包通过网络层向下发送时,通过路由表和目的IP地址确定数据包的下一跳的协议地址,也就是下一跳的IP地址,根据下一跳的IP地址找到它的硬件地址,也就是MAC地址。在以太网中,就需要地址解析
一些较低层(可能是硬件驱动程序)必须咨询地址解析模块将目标协议地址(也就是下一跳IP地址)转换为一个48位以太网地址(也就是MAC地址)
地址解析模块尝试在ARP缓存表中找到。如果找到,它会将相应的48位以太网地址返回给调用方(硬件驱动程序),然后调用方发送数据包(把MAC地址封装进报文中)
如果没有,它会通知调用者,并生成一个类型字段为ether_type$ADDRESS_RESOLUTION的以太网数据包(链路层首部16位协议类型设置为ARP,值为0x0806)
然后地址解析模块
- 将ar$hrd字段(16位硬件地址类型)设置为Ethernet(值为1)
- 将ar$pro(16位协议地址类型)设置为正在解析的协议类型(IP协议,值为0x0800)
- 将ar$hln(8位硬件地址长度)设置为6(48位以太网地址中的字节数)
- 将ar$pln(8位协议地址长度)设置为协议地址的长度(IPv4地址长度为4个字节)
- 将ar$op(16位操作类型)设置为REQUEST(值为1)
- 将ar$sha(发送方硬件地址)设置为它自己的48位以太网地址
- 将ar$spa(发送方协议地址)设置为它自己的协议地址
- 将ar$tpa(接收方协议地址)设置为它试图访问的主机的IP地址(也就是下一跳的IP地址)
- 它没有将ar$tha(接收方硬件地址)设置为任何特别的东西(设置为全0),因为它正试图确定这个值
它可以将ar$tha(接收方硬件地址)设置为硬件的广播地址(全F),如果这对于实现来说很方便的话
最后,它会将此数据包(ARP请求报文)广播到广播域内的所有主机
报文接收
当收到地址解析数据包时,接收以太网模块将数据包交给地址解析模块,该模块通过类似于以下的算法。否定条件表示处理结束并丢弃数据包
接收方以太网模块收到ARP请求报文时,会把数据包交给自己的地址解析模块
怎么知道是交给地址解析模块呢,因为ARP请求报文的链路层首部里协议类型为ARP
地址解析模块处理数据包的算法如下:
接收方大致的流程如下:
-
我支持这个硬件地址类型吗?—YES
-
我支持这个协议地址类型吗?—YES,这其中还有可能会检查协议地址长度
在这一步YES后,还会先把一个标志位Merge_flag设置为false,然后在ARP缓存表里查找是否存在发送方协议地址,如果存在就更新ip-mac,同时把标志位Merge_flag设置为true
- 我是目的协议地址吗?—YES
在这一步YES后,如果Merge_flag为false,就会把发送方协议地址-发送方硬件地址,存入ARP缓存表中
- opcode是REQUEST吗?—YES
在这一步YES后,接收方把自己的硬件地址(MAC地址)和协议地址(IP地址)放入发送方字段中,把ar$op字段设置为REPLY,将数据包发送给发送方,这样发送方接收到ARP_REPLY后就知道接收方的MAC地址了
从上面接收方的处理流程可以看出:
-
接收方在确认协议地址类型正确后,会先查看ARP缓存表中是否已存在发送方的IP-MAC,如果存在则更新,如果不存在,也没有存入,要到下一个流程才存入
-
接收方在确认目的协议地址正确后,会先查看标志位Merge_flag为false,才会存入发送方的IP-MAC,Merge_flag为false意味着自己的ARP缓存表内不存在发送方的IP-MAC
-
最后一步判断完操作类型是REQUEST,才会回复REPLY,说明接收方收到ARP请求报文后,是先更新或存入IP-MAC,然后才回复报文的
另外请注意,RFC并不是硬性规定,所以很多协议栈处理逻辑有所不同很正常,具体可以阅读我之前写过的一篇《ARP报文的存入条件和回复条件》
Why This Way
下面这段话描述了为什么用这种方式处理ARP数据包
为什么不用定期广播的形式寻址呢,可以但没必要,主机通常并不会相互交流,只有在有需要时通信,所以只要在通信前寻址一次,然后缓存到自己的ARP缓存表,那么短时间内的连续通信就可以不用再发送ARP请求了
理论上,长度字段是多余的,因为协议地址的长度应该由硬件类型决定,所以它在协议栈中是可选的检查项。opcode操作类型是为了判断这是一个请求(可能导致回复)还是对之前请求的回复。发送方硬件地址和发送方协议地址是绝对必要的,因为正是它们被放入了接收方的ARP缓存表中,这样就实现了一次ARP请求和回复让发送方和接收方都知道了彼此IP-MAC
通过ARP数据包的形式缓存的IP-MAC,是ARP缓存表中的动态条目,每条动态条目会有一个老化时间,当老化时间结束时,如果没有更新,则自动删除,如果有更新,则重新启动老化时间计时器,当然,这些功能的实现并不属于本协议文档的范围
其他未提及部分,请自行翻阅RFC 826文档