【Linux】数据链路层:以太网协议

约束不等于压迫,冷静和理性不等于冷淡和麻木。

文章目录


一、以太网帧 和 局域网转发数据包

1.局域网转发的原理(基于以太网协议)

(1)IP提供了将数据包跨网络发送的能力,这种能力实际上是通过子网划分+目的ip+查询节点的路由表来实现的,但实际上数据包要先能够在局域网内部进行转发到目的主机,只有有了这个能力之后,数据包才能跨过一个个的局域网,最终将数据包发送到目的主机。
所以跨网络传输的本质就是跨无数个局域网内数据包转发的结果,离理解整个数据包在网络中转发的过程,我们只差理解局域网数据包转发这临门一脚了。
(2)而现在最常见的局域网通信技术就是以太网,无线LAN,令牌环网(这三种技术在数据链路层使用的都是MAC地址),早在1970年代IBM公司就发明了局域网通信技术令牌环网,但后来在1980年代,局域网通信技术进入了以太网大潮,原来提供令牌网设备的厂商多数也退出了市场,在目前的局域网种令牌环网早已江河日下,明日黄花了,等到后面进入移动设备时代时,在1990年,国外的一位博士带领自己的团队发明了无线LAN技术,也就是wifi这项技术,实现了与有线网一样快速和稳定的传输,并在1996年在美国申请了无线网技术专利。
今天学习的正是以太网技术。

(1)下面是MAC帧的格式,MAC帧主要有两类,一类是有效载荷为正常的从上层传输下来的IP报文,另一类是数据链路层自己的有效载荷,包含ARP请求/应答 或 RARP请求/应答,这类报文在讲ARP协议时会重点谈论,ARP协议和以太网技术是当前有线局域网通信中最重要的两个部分。第二类的报文末尾有PAD字段,该字段为填充字段,用于填充报文长度,因为MAC帧层规定有效载荷最小下限不能低于46字节,所以需要填充18字节的长度,但在接收方填充字段会被直接忽略掉,PAD并不会对通信产生实际影响,我们可以直接忽略掉他。
(2)MAC帧包括6字节的目的MAC地址和源MAC地址,以及两个字节的类型字段,0800是普通MAC帧,0806和8035分别代表封装ARP和RARP请求应答的MAC帧,以及4字节的CRC校验和,这个CRC校验和在传输层,网络层,数据链路层我们都见到过,算是老朋友了。MAC帧的构成还是非常简单的,最重要的字段就是类型和源MAC地址和目的MAC地址。
(3)谈论协议我们一直离不开的两个问题,如何将报头和有效载荷做分离呢?如何进行分用呢?
MAC协议采取的是定长报头的方式来将报头和有效载荷作分离,读取时可以先正向读取14字节的报头数据,然后再反向读取4字节的剩余报头数据,这样就可以将报头和有效载荷做分离了,分用时,我们依靠的是类型字段来进行分用,如果0800就向上交付给IP协议,如果是0806就向上交付给ARP协议,如果是0835就向上交付给RARP协议


以下是数据链路层,网络层,传输层向上分用的过程,分用可以体现在他们各自协议的报头字段里面,比如以太网协议的16位类型字段,0800,0806,0835,IP协议的8位类型字段,ICMP是1,TCP是6,UDP是17,TCP协议或UDP协议的16位目的端口号。

(1)当m1构建了一个MAC帧发送到局域网中时,局域网中的每台主机都会收到该数据帧,但m2~m7主机在收到数据帧,并将数据帧的报头读取之后,发现目的MAC地址并不是他们自己的MAC地址,所以这些主机在收到数据帧后,都会在自己的数据链路层将报文丢弃,但只有m8主机不会丢弃,他一看报头中的目的MAC地址是他自己,此时m8就会将报头和有效载荷做分离,然后向上进行分用,直到最后传递到m8的应用层。反过来m8如果想给m1主机回复报文,原理也是一样的,他也会封装一个目的MAC地址为m1的数据帧,然后将该数据帧发送到局域网中,局域网中只有m1收到数据帧不会进行丢弃,其他主机在自己的数据链路层就会将该数据帧丢弃。这就是以太网技术在局域网中通信的原理。(栗子:老师叫张三回答问题,全班同学都听到了,但其他同学都没有站起来回答问题,只有张三同学站起来回答了问题)
(2)在局域网中,网卡有一种模式叫做混杂模式,我们的网卡默认是不会开启这种模式的,这种模式的特点就是不放弃任何数据帧,直接向上交付给网络层,这也是许多局域网抓包工具的原理

2.以太网MTU与MAC地址

MAC地址是机器的物理地址,6字节的MAC地址在全球范围内具有唯一性,因为48个比特位构成的MAC地址的个数是17w亿个地址,具2020年底统计,全球的入网设备大概有300亿台,所以MAC地址不像ipv4地址那样紧缺,MAC地址绝对是足够的!
数据包在进行网络中路由转发时,ip地址描述的是源主机和最终目的主机,而MAC地址描述的是,下一跳这个区间的起点和终点。

在局域网中,如果数据特别长,则会增大数据碰撞的概率,就像战场上的士兵如果体格越大,则目标越大,被子弹击中的概率也就越大,而发送数据帧时,数据也要有一定的价值,总不能数据太短了吧,一句话分成三句话说?所以数据传输时,太大也不好,太小也不好,以太网协议规定了数据帧有效载荷的大小区间,最大不能超过上限MTU1500字节,最小不能低于下限46字节


3.
(1)不仅仅发送主机可能会对报文做分片,路径上的路由器也可能对报文做分片,例如下图中发送主机为了第一条数据传输的吞吐量,使用FDDI技术提高了MTU的值,将MTU的值设置为4532字节,但当路由器转给目标主机时,路由器的以太网协议规定了MTU是1500字节,所以此时路由器会在自己的网络层对IP报文做分片。
除了这样的情况外,还有可能出现主机在MTU为1500的情况下,已经在IP层对报文做出了分片,但有可能路径上的路由器的MTU为500,此时路由器可能还会继续对已经分片的报文继续做出分片。(2)如果我们不想让路由路径中的节点对报文继续做分片,则我们可以将IP报头中的3位标志字段设置为禁止分片,如果路上遇到某个节点的MTU过小,想对报文做分片时候,但报文却禁止被分片,此时路由器就会丢弃该报文,当发送端长时间没有收到应答报文段时,发送端会进行超时重传报文,此时报文就会重新规划路由的路径,寻找到一条最大吞吐量的路径出来。
(3)如果你不想找最大吞吐量的路径,而是想找出最快速度传输的路径,则我们可以降低数据量的大小,IP层在路由选择路径时,是可以找到最快传输速率的路径的。

其实下面这些话题我们都讲过,无非就是MSS和SMSS之间的关系,以及滑动窗口发送的数据段的多少,为了防止IP层分片,TCP头部选项字段中包含了通信双方互相协商MSS大小的选项kind=2,以及IP分片时,对于数据丢包的影响。其实这些我们在之前的IP层和TCP层都讲过了,这里简单提一下,如果有遗忘的,可以移步我之前写的文章。

【Linux】传输层协议:UDP和TCP

【Linux】网络层协议:IP

二、局域网中的数据碰撞

1.如何解决局域网中的数据碰撞?(碰撞检测和碰撞避免算法)

(1)局域网中,一定是多台主机同时在发送数据的,而只要所有主机都在发送着数据,就会形成数据之间的干扰,在计算里面我们称为数据碰撞。(老师叫张三回答问题,结果全班同学都在叽叽喳喳的说,张三听不清老师在说什么,其他同学互相之间说话也会互相干扰)
(2)所以数据链路层规定,任何时刻,只能有一个主机在发送消息,如果有多个主机在同时发,这些数据发送碰撞后,这样的数据就变成了无效数据。
(3)如何判断主机发送的数据发生了碰撞呢?m1发送的数据,m1自己也会收到,如果m1接收到的数据和自己发送的数据不一致的话,则接收的数据帧在进行CRC校验时,一定会出错,此时就说明m1发送的数据帧发生了碰撞。所以局域网还有另一种称呼,叫做碰撞域。

如何保证一个碰撞域中,任意时刻只能有一个主机在发送数据呢?
其实不同的局域网通信技术,有着不同的解决方案。
(1)令牌环网采取的方式是向局域网中流放一份令牌环数据,只有持有该令牌环数据的主机才能发送消息,发完消息之后,再将令牌环数据丢到局域网中,这样就可以保证任意时刻,都只会有一个主机在发数据,不会产生多个主机同时发数据而造成碰撞的问题。
(2)当A主机和B主机在发送数据时,发生了碰撞,此时会触发以太网协议的策略,策略也很简单,就是暂时不让A主机和B主机发送数据,让他们各自都等一等再发,等待的时间随机,视情况而定,在A和B等待的时候,局域网中的其他主机就可以发送数据帧了,当A和B等待结束之后,重新向局域网中发送数据,碰撞的概率就会非常低了。
(3)当数据发生碰撞后,以太网执行的策略,我们称之为碰撞检测和碰撞避免算法,其实这个策略很简单,说白了就是等一等再发,但你不要高估了局域网中各个主机发送数据的量,也不要低估了光电信号(二进制数据)在局域网中传播的速度,局域网并没有那么的大,容纳的主机数并不是非常多,所以对于飞快的光电信号来讲,发生碰撞的概率本身就低,所以等一等再发这样听起来很不靠谱的策略,在实际中却是很有效的。
其实早在1980年的时候,当时以太网技术推出时,很多人都不看好以太网的技术标准,不仅我们觉得碰撞检测和避免的算法也太随意了一些,当时的人们也这么觉得,并且当时有相关的专业机构也得出过结论,从理论上来讲,令牌环网碰撞避免的效率和可靠性应该更高一些,但当实际中真正采纳以太网时,才知道以太网是很香的,随后以太网就大面积快速的推广,而令牌环网却慢慢的变得无人问津。

既然局域网中多主机在发送数据时,可能产生数据碰撞,那是不就意味着,如果我搞一台主机,不断的向局域网中发送垃圾数据,同时这台主机不执行碰撞检测和避免的算法,那这个局域网中的其他主机是不就一直不能发送数据呢?也就意味着这台主机黑掉了这个局域网?
确实是这样子的,网上是有这样的工具的,但我不知道这个工具是啥,如果你有的话,可以尝试在自己家里面的局域网中搞一下,看是否能够黑掉你家的局域网。

2.如何重新看待局域网?(系统视角)

我们上面说,任何时刻在局域网中只能有一个主机在向局域网中发送数据,那我们不就可以把局域网看作临界资源吗?而像碰撞检测和避免算法能够保护临界资源,保证只能有一个主机在访问临界资源,那这不就相当于互斥锁或条件变量吗?而所谓的令牌环数据,不也就相当于互斥锁吗?谁拿着锁谁才能访问临界资源!
所以系统和网络是不分家的,可能在代码层面上两者是划分开的,但在设计理念,和某些策略的设计思想上,两者一定是有重叠的!

3.局域网很大,如何降低数据的碰撞概率(交换机划分碰撞域+硬件转发)

局域网一定不能很大,因为大了之后,主机数就会变多,发生碰撞的概率就会变高。
手机的wifi其实就是无线式的以太网,在学校中比如操场举办活动,大家都去参加,此时大家都连接的是校园wifi,这个时候,大家就会同处于一个局域网中,进行网络数据传输时,发生碰撞的概率就会变得很高,而一旦发生碰撞,就会执行碰撞检测和避免算法,手机或其他入网设备都会等一等,而直观上体现出来的就是我们感觉网速很慢,感觉网太卡了。
就算手机用的是流量,其实也会很卡,因为你所处的环境周围可能只有一个基站,比如你在上大课的时候,有很多同学用的都是联通流量卡,你们坐在一间大教室里面,那你们访问互联网时,你和其他同学的数据其实都会被转发到附近的联通基站,而基站的功率一定是有上限的,你和你的同学都在向基站发送数据,此时数据可能在无线信道上发生数据碰撞,所以你的手机上网就会很卡,除此之外还有可能是因为基站负载已经比较高了,无法及时处理数据请求,此时就会导致网络延迟增加,直观上也是我们的手机感觉会很卡。

下面是我家附近的一个基站的图片,不知道是哪个运营商的,哪天过去看一眼。

2.
那如果局域网就是很大,比如学校里面,我还想提高网络传输效率,降低数据碰撞的概率,有什么其他办法吗?有的,引入交换机即可
(1)交换机会通过划分碰撞域的方式来降低数据碰撞的概率,任意时刻,每个碰撞域只有一个设备可以发送数据,减少碰撞域中的设备,以此来降低发送数据时碰撞的概率。
(2)交换机具有硬件转发的能力,可以将数据直接转发到目的设备,而无需将数据广播到整个局域网当中,这种点对点的方式可以减少数据包在网络中的传播范围,降低碰撞概率
比如,当左侧的主机在互相通信时,交换机不会将左侧的消息转发到右侧的碰撞域,如果左侧主机在通信时,数据发生了碰撞,同样交换机也不会将碰撞数据转发到右侧碰撞域,避免碰撞数据的进一步传播。右侧的情况与左侧相同,而当左侧要和右侧主机通信时候,此时交换机可以将数据直接转发到右侧的目的设备。

三、ARP协议

1.ARP将已知的ip地址转换为未知的MAC地址的过程

之前我们谈论以太网通信时,说过在局域网内我们应该将数据包路由到下一跳位置,以这样的方式来跨多个网络进行数据包的传输,但想要将数据包发送到下一跳位置,一定是数据帧在网线上进行传输,而想要以数据帧的方式进行传输,则网络层一定要向下交付,然后封装帧报头,帧报头中有源MAC地址和目的MAC地址字段,源MAC地址好解决,但发送方怎么知道下一跳节点的目的MAC地址呢?没人告诉过数据链路层目的MAC地址是多少啊?当时我们是站在上帝视角,说数据包发送到下一跳主机,但实际通信时,一定是要封装MAC报头的啊,目的MAC地址都不知道,怎么封装MAC报头呢?其实这里面就缺了一个关键角色,ARP协议,虽然我们不知道目的MAC地址是多少,但我们知道下一跳的ip地址是多少啊!而ARP协议做的就是将ip地址转换为MAC地址的工作,知道MAC地址后,就可以将IP报文,向下交付,在MAC层封装好MAC帧报头,然后再通过以太网接口Iface,将数据帧发送到目标主机。
我们可以将ARP协议理解为在数据链路层中,MAC层的上面,如果发送方不知道下一跳节点的MAC地址,则可以先通过ARP协议获取到下一跳节点的MAC地址,然后再交付给MAC层,封装MAC帧报头,最后发送到局域网中。

下面就是封装ARP请求/应答的MAC帧格式,硬件类型指的是链路层的网络类型,1为以太网,协议类型表示要转换的地址类型,该值为0x800,表示ip地址,硬件地址长度的值为6,表示以太网MAC地址的长度大小,协议地址长度的值为4,表示ip地址的长度。这四个字段值都是固定写法,没什么价值。
op字段为1表示ARP请求,op字段为2表示ARP应答报文,后四个字段,只有目的以太网地址是不知道该填什么的,在未得到目的MAC地址值时,一般将该字段设置为全F,最核心的字段就是这5个字段了。


无论你的局域网技术是什么,都需要有将ip地址转换为MAC地址的能力,因为无线LAN,以太网,令牌环等技术使用的都是MAC地址。
因为ARP协议是在MAC帧上层的,所以以太网帧格式,除了封装IP报文外,还可以封装ARP请求或应答。

(1)其实ARP请求的原理和以太网技术很相似,m1主机在ARP层就填充好了ARP报头中的各个字段,最主要的一个字段就是目的ip(其实是下一跳节点的ip地址,并不是最终目标主机的ip地址),填充这个字段其实并不难,查一下节点的路由表就可以确定出下一跳节点的ip地址,填充好之后,向下交付到MAC层,MAC层封装好MAC报头后,会将MAC帧发送到局域网中。
(2)由于MAC报头里的目的MAC地址是全F,所有局域网中的所有主机都会收到该数据帧,并将报头和有效载荷做分离,然后再看ARP报文的op字段,发现是1,则说明是ARP请求,然后所有的主机都会对比自己的ip地址和ARP请求中的ip地址是否相等,如果相等,则发现这个ARP请求是发送给我这台主机的,接下来这台主机就会读取剩余的ARP报头内容,这样就完成了ARP请求的过程(3)然后接收主机会构建ARP应答发送回源主机,此时构建ARP应答就简单了,因为读取ARP请求时,接收主机就已经知道了发送端的MAC地址和ip地址了,所以构建ARP应答只需要将自己的ip地址和MAC地址填充到ARP应答报文中,并把op字段填充为2表示ARP应答报文,再把其他固定的字段填充一下,最后再封装一层MAC帧报头,然后发送到局域网中。
当所有的主机都收到该报文时,非目标主机在MAC层就会丢弃该报文,因为读取MAC报头后,就发现目的MAC地址与自己的MAC地址是不相符的,只有m1主机收到该报文后,才会拆分报头和有效载荷,将ARP应答向上交付给ARP层,m1读取完ARP应答的内容后,就知道下一跳节点的MAC地址了,此时就可以堂堂正正的封装IP报文,将类型为0800的数据帧发送到局域网中了。


4.
(1)还有一种情况是,我们只知道对方的MAC地址,不知道其ip地址,这种情况出现的概率非常低,一般可能出现在网络管理员进行局域网管理时,如果他发现某个路由器发不出去数据帧了,他现在只知道路由器的MAC地址,他想查查自己当时给路由器配的ip地址是不是发生变化了,那么此时就需要另一台主机通过RARP协议,向路由器发起RARP请求,以此来获得路由器的ip地址。
(2)RARP的格式与ARP相同,原理其实也是类似的,也是通过广播的方式来让目的主机收到RARP请求,目的主机然后将自己的ip地址封装成RARP应答报文发送回源主机,原理和ARP类似,这里不再过多赘述。

2.ARP缓存

(1)当发送端主机会先在IP层通过目的ip+路由表的方式,确定出下一跳节点的ip地址,然后向局域网中发送数据帧,但如果该主机不知道下一跳节点的MAC地址时,则可以进行ARP请求,将已知的下一跳节点的ip地址转换为未知的MAC地址,然后发送端主机就可以封装MAC帧,进行数据传输了。
(2)一个局域网并不是很大,所以路由器完全可以给他所管理的局域网中的所有主机都发送ARP请求,先提前获取到所有主机的MAC地址,然后构建一张ARP缓存表,将每台主机的ip地址和MAC地址的映射关系作为一个条目,保存到ARP缓存表中。这样下次如果有数据包到达路由器,路由器在自己的IP层确定好数据包的下一跳位置后,则可以查询ARP缓存表,通过下一条节点的ip地址映射得到MAC地址,无须再次进行ARP请求,得到MAC地址后,则路由器就可以向下将IP报文封装成MAC帧,发送到局域网中,下一跳节点会收到这个MAC帧,进行数据包的后续处理。
(3)由于ARP的需求非常大,为了不让每个节点在发送数据帧前,都频繁的进行ARP请求,除了路由器的ARP缓存表外,只要你先前和局域网中的一些主机通信过,那么下次再向其发送数据包时,无须进行ARP请求,主机自身会将他的MAC地址缓存下来,以便未来可能使用。
(4)需要注意的是,这种缓存是分钟级别的,过段时间会被丢弃掉,因为局域网中的ip地址是变化的,DHCP会动态分配入网设备的ip地址,ip地址变化,则原来的ip与MAC的映射关系就会变化,所以ARP缓存是分钟级别的,当ip地址变化时,对应的映射关系条目也会自动被丢弃掉。

下图中右侧部分的arp缓存分别是我的云服务器和windows机器的结果

3.中间人的ARP欺骗

其实成为中间人很简单,只要不停的强迫通信双方更新arp缓存即可,让他们把arp缓存更新为中间人的MAC地址,然后中间人将他们发送的数据包转发给对方,这样就完成了ARP欺骗,从而让中间人获得双方通信的数据。
不过我们也有相应的解决方案,那就是HTTPS协议,对数据包中的内容进行加密,下面有我之前写的文章链接,详情可移步。

【Linux】应用层协议:HTTP和HTTPS

如果我们想要自己玩,其实可以不用成为中间人,如果你想打掉某台主机的话,只需要抓到这台主机向路由器发送的ARP请求包即可(可以提前踩点,拿到路由器的ip地址,对抓到的包进行过滤,找出目的ip为踩点时的路由器ip的请求包),然后构建一个ARP应答,将里面的目的MAC地址胡乱写一个值,返回给这台主机,此时这台主机就不能联网了,因为他发送的数据帧找不到路由器了,数据帧里面的目的MAC地址是错误的。

相关推荐
JunLan~3 小时前
Rocky Linux 系统安装/部署 Docker
linux·docker·容器
方竞4 小时前
Linux空口抓包方法
linux·空口抓包
Estar.Lee4 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
傻啦嘿哟4 小时前
代理IP在后端开发中的应用与后端工程师的角色
网络·网络协议·tcp/ip
sun0077004 小时前
ubuntu dpkg 删除安装包
运维·服务器·ubuntu
海岛日记5 小时前
centos一键卸载docker脚本
linux·docker·centos
向阳12185 小时前
Dubbo HTTP接入之triple协议
网络协议·http·dubbo
oi775 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器