Linux网络编程_数据链路层MAC帧协议与ARP协议
引言
前面学习应用层,功能是实现业务逻辑;传输层,功能是提供进程到进程之间的端到端通信,确保数据传输的正确性,可靠性;网络层,功能是提供主机到主机的逻辑通信(告诉主机/路由器该将报文传到哪里,通过什么路由传到什么目的地);而今天学习的数据链路层,功能是提供相邻节点之间的可靠传输(告诉主机如何传递到下一位置)
MAC帧协议
其实数据链路层更精确的说,解决的是如何在内网实现通信,而MAC帧就是目前常用的实现方案,下面直接介绍MAC帧协议

- 目的地址:6字节,填充的是目的主机的MAC地址
- 源地址:6字节,填充的是源主机的MAC地址
- 帧类型:2字节,填充的是帧类型(网络层协议或ARP协议等),比如0x0800表示IP协议,0x0806表示ARP协议,0x8035表示RARP协议
- 帧内容:大小需要在46-1500字节之间
- CRC校验码:4字节,用于检测数据是否正确
可以看到,MAC帧协议的报头是固定大小的,由此便可轻松实现报头封装与分离;而其中的帧类型字段,可以让操作系统决定具体的处理正文的方式(如何分用)
MAC地址
原则上每台主机的MAC地址都是全球唯一的,长度为6字节,但由于MAC具备随机性,所以就算全球唯一,也无法把它当作IP进行全网直接通信(且仅是原则上唯一,实际实现不保证)
ARP协议
ARP协议,即地址解析协议,其功能就是把IP地址转换为MAC地址,主要注意的是,这并不代表IP与MAC之间有关联,实现转换的方案其实是向局域网内发送广播帧,同时,ARP协议实际位于数据链路层,结构大致如下:

需要注意的是,ARP报文本身无需正文,也就是说无需网络层的数据,且APR也要封装为MAC帧才能进行发送,也就是说,ARP需要封装MAC帧报头,下面来介绍ARP报头:

- 上图为带有MAC帧报头的ARP请求/应答,没错,ARP请求和应答共用相同的报头结构,且帧类型均填写0806
- 硬件类型:通常填1,代表以太网,代表这次ARP过程是在以太网中进行的
- 协议类型:常填写为0x0800,代表IP协议
- 硬件长度:常填6,表示硬件地址长度(常用以太网,一个MAC地址为6字节)
- 协议地址长度:常填写为4,表示协议地址长度(常用IPv4,一个IP地址为4字节)
- op:如果op为1,则代表ARP请求,若为2,则代表ARP应答-》
ARP请求应答用的是同一协议 - 发送端以太网地址:填充发送端MAC地址
- 发送端IP地址:填充发送端IP地址
- 接收端以太网地址:填充接收端MAC地址,不知道时填充0xFFFFFFFFFFFF(6字节全1)
- 接收端IP地址:填充接收端IP地址
局域网通信
-
网络通信,本质就是在各个局域网中传递MAC帧,而处于单个局域网的多台主机,其中某台主机发送数据后,当前局域网中的所有主机都有能力收到该MAC帧,但非目标主机默认情况会通过对报头目的地址字段的判断将MAC丢弃
-
局域网就是一个碰撞域,同一时刻仅能发送一个MAC帧,若同一时刻同一局域网出现多个数据帧,则会造成碰撞,为此会有对应的碰撞检测碰撞避免机制(类似传输层拥塞控制),也就是说,
局域网是临界资源,也正因此,需要将数据帧传送个数与大小进行相应的限制,这也是帧内容被限制在46~1500字节的原因之一 -
网络通信本质就是传递MAC帧,也就是说,发送方需要先知道接收方的MAC地址才能精准将数据进行发送,值得一提的是,发送方是在最开始就知道接收方的IP地址的(如C端申请访问S端,之后NAT进行数据传输时会替换IP与端口号),换言之,只需要一个
能够将IP地址转换为MAC地址的协议,即ARP协议,下面将会重点进行说明 -
局域网通信过程(ARP请求与应答):

- 首先,路由器从外网收到了一个报文,查路由表后发现应发送给主机E,但此时路由器只知道E的IP地址,并不知道E的MAC地址,此时就需要路由器发送一个ARP请求:将ARP报头填为1 0x0800 6 4 1 MACR IPR 0xFFFFFFFFFFFF IPE;MAC帧报头填写:0xFFFFFFFFFFFF(即广播地址) MACR 0x0806,然后将该报文发送到局域网中
- 局域网内各主机接收到ARP报文后,发现MAC帧目的MAC为广播,会拆除MAC报头,然后ARP传送至自身操作系统ARP模块,然后
根据op字段判断出该报文为ARP请求,则会查看目的IP,发现非自身IP,则丢弃该报文,若为自身IP,则构建ARP应答报文 - ARP应答报文:由于请求报文中已经包含了源IP,源MAC以及目的IPE,所以这里直接填充当前主机MACE,即为1 0x0800 6 4 2 MACE IPE MACR IPR;MAC帧报头填写:MACR IPR 0x0806
- 局域网内所有主机都会收到该ARP应答,但在数据链路层MAC帧协议部分就会判断目的MAC地址是否是自己,若不是,则默认丢弃,若是(此处为路由器R),则从报文中拆出ARP部分交给操作系统ARP处理,
先判断op,发现是ARP应答,然后找到发送端MAC地址后,即获取了主机E的MAC地址,则接下来使用该MACE和IPE向E主机传送数据报文即可 每台主机中都会在一段时间内(分钟级)存储其他主机的IP地址与MAC地址的映射关系,并非每次发送报文都需要重新发送ARP请求- 从上述过程也能看出,
局域网中,任何主机都可能收到ARP请求或ARP应答 非目标主机接收ARP请求与ARP应答的丢弃层级不同,请求是在操作系统ARP处理层丢弃,响应是在操作系统MAC帧处理层丢弃
ARP欺骗
首先,当主机收到新的IP与MAC的映射关系后,会直接更新自身映射表,而由此,就可能导致中间人攻击------ARP欺骗,具体流程如下图:

主机A先开始与路由器R通信了一段时间,此时,出现了主机M,其伪造ARP报文,告知A主机IPR的MAC更新为了MACM,同时伪造ARP,告知路由器R IPA的MAC为MACM,则由此,今后主机A向R发送数据时,都会先经过中间人M,而M不仅可以窃取拦截数据,还可以进行篡改,且通信双方甚至无法察觉该中间人的存在
NAT与NATP
在网络层博客中已经对NAT有了初步说明,这里会继续进行补充,首先,NAT在将自身主机源IP替换为下一跳(当前局域网目标路由器)IP时,也会将端口号进行替换,具体来说,NAT过程中会在路由器中建立如下表项:

这里假设左侧是内网,路由器WAN是外网(实际单纯在内网中也会进行该行为),客户端A发送数据到下一跳(路由器),在路由器中则会生成对应表项,将A的IP地址替换为路由器的WAN地址,且端口号可能会发生变化;对于客户端B,也对应出了一组键值,B的IP同样被替换为了路由器的WAN地址,端口号被替换为了1026,其实,端口号是否与源端口相同不重要,最关键的是,需要保证每个客户端 + 端口号 唯一映射 路由器WAN地址 + 端口号,而由于这里的WAN只有一个,且AB端口号相同,所以为保证唯一映射,B的端口号就被替换为了1026,而这张表则被称为NAPT表,且显然,在LAN与WAN均为内网的情况下也可采取该方案,而通过该方案,就可以保证服务端应答报文能正确反馈(索引)到对应客户端,如此,便打通了请求报文发送流程与响应报文接收流程(内网可以通过逐个唯一键值(IP + 端口号)发送报文至外网,外网也可通过同样的逐个唯一键值(IP + 端口号)找到发送端,将响应报文发送回来)-》因此也能得出,若内网不主动向外访问,则路由器不会构建NAPT表,则没有键值,也就是说外网无法直接访问内网
MTU与MSS细节
- 中间节点(如路由器)在传输MAC数据时,也可能因自身MTU较小,需要将其中的IP数据报再次分片 + 重新封装为MAC帧,但是由于IP协议设计良好,所以仍能保证正确进行分离与组装
- MSS为TCP协议封装的最大报文长度,这点不仅仅是在传输方面,在接收方面也是如此,也就是说,若发送端MSS大于接收端MSS,则可能出现问题,为此,操作系统会在TCP三次握手时获取双方的MSS值,此后,通信双方会协议好使用其中最小的MSS值进行报文封装与数据传输,注:这里的MSS基本就是通过MTU算出来的
- MSS与MTU的关系:
