IP和数据链路层之间的关系
引言
在IP一节中,我们说IP层路由(数据转发)的过程,就像我们跳一跳游戏一样,从一个节点,转发到另一个节点
它提供了一种将数据从A主机跨网络发到B主机的能力
什么叫做跨网络???
本质是要经历很多子网或者局域网
图来自小林网络coding
也就是说节点与节点之间,不要看只是两台主机
更准确的说,它是同一个局域网内两台不同的主机(两两之间各属于一个子网)
假如我们想要将数据从主机B发送到主机C,我们说IP层为我们提供路径选择,即从哪个节点,跳到哪个节点(跨网络)
假如数据出现错误,我们有TCP层保证可靠性
现在还有一个很关键的问题
在同一个局域网内,为什么主机B会向路由器发消息,而不会向其它人发消息呢?
这就是数据链路层解决的问题——在同一个子网内,数据如何发送
所以我们之前说IP层拥有将数据从A主机跨网络发送到B主机的能力其实并不准确,只不过是讨论该层的时候,已经默认包含了下层的能力
IP层与数据链路层两者联合起来,才拥有将数据从A主机跨网络发送到B主机的能力!
数据链路层的定位和作用
我们可以举回上一次旅行的例子来进一步加深理解
假如我们要从广东东莞出发,去新加坡旅行,我们往往不是一步到位,直接坐飞机就可以到达
相反,我们制定了⼀个行程表,先乘坐公交车到深圳,再坐高铁到香港,然后从香港坐飞机到新加坡
公交车票和高铁票都是去往特定的地点的,每张票只能够在某⼀限定区间内移动,此处的「区间内」就如同通信网络中数据链路
在区间内移动相当于数据链路层,实现区间内两个节点传输的功能
为什么要先到深圳,再到香港,最后才到新加坡?
这些节点的选择是谁来决定的?
这就是我们IP层实现的功能,它就相当于我们的行程表
两者相互搭配,才可以实现从一个地方,跨不同区域到达另一个地方的目标!
总结一下,数据链路层的定位:
用于两个设备(同一种数据链路节点)之间进行传递
以太网
那我从东莞到深圳,除了坐车之外,可不可以坐地铁呢?或者你骑自行车都可以!在同一个区域内,一个节点到另外一个节点的方式有很多种
同样的,在同一个局域网内,一台主机到另外一台主机的方式有很多种,可以说是千差万别,这也是为什么数据链路层不可能被整合像我们的TCP/IP层一样,在OS操作系统内部实现
常见实现的局域网通信技术有下面三种:
以太网:
以太网是一种应用最普遍的计算机局域网技术
它不是一种具体的网络, 而是一种技术标准;
既包含了数据链路层的内容, 也包含了一些物理层的内容
例如以太网中的网线必须使用双绞线; 传输速率有10M, 100M, 1000M等
令牌环网:
令牌环网常用于IBM系统中,在这种网络中有一种专门的帧称为“令牌”,在环路上持续地传输来确定一个节点何时可以发送包.
无线LAN/WAN:
无线局域网是有线网络的补充和扩展,现在已经是计算机网络的一个重要组织部分
像我们的手机连wifi,访问路由器,不用接线吧?都是无线进行操作的
但我们说不用担心,虽然数据链路层存在不同的局域网通信技术,但是我们的路由器可以替我们屏蔽底层网络之间的差异,达到无障碍适配
图来自博主2021dragon
路由器内部就自带对应不同局域网通信技术的驱动程序,假如根据查找对应的路由表,发现目的IP主机不在这个网络而且采用的是不同的通信技术,就会为我们重新进行对应的封装
这也是为什么我们手机明明采用的是无线LAN/WAN通信技术,但是可以将我们对应的数据发送给对应路由器,和其它底层使用以太网的有线设备进行数据交流.
(手机无线给QQ发消息,电脑端QQ可以收到;或者我们手机微信文件共享给台式电脑,在底层其实都是这个原理.)
类似的技术还有:
虚拟地址空间: 屏蔽了内存之间的差别,让所有的进程看到的都是同一块内存,并且这块内存的布局都是一样的。
一切皆文件: 通过文件结构体和函数指针的方案,让我们能够以对待文件的方式对待某些资源
局域网通信原理
MAC地址
有了上面的铺垫后,我们就可以开始讲解局域网通信原理
我们先来看一个小故事
假如今天大家都在教室内上课,老师突然喊了一句,张三,为什么你的作业昨晚没有按时提交?
张三听到后站了起来,回复道:“不对吧,我记得我昨天明明交了啊!”
老师听到后,给出对应的回复:“好的,那我回去再看看.”
上述故事其实就很好阐述了我们局域网通信的基本原理
第一,老师说话,同学们怎么知道老师叫的是谁呢?
答案是名字,并且此时每个人的名字都具有唯一性
第二,老师喊话张三的时候,其他同学听到消息了吗?
答案是听到了,只不过因为叫的不是自己,所以没有进行对应站起来回答问题的操作
类比到我们局域网通信当中来,每一台主机都有着自己的网卡,一张网卡上就对应有一个全球唯一的MAC地址,它就相当于我们每个同学的名字
在linux下,我们同样可以输入ifconfig指令,查看对应的MAC地址
其中ether是以太网的意思,总共48位
当一台主机在局域网内发消息时,所有人其实都收到消息了,只不过由于匹配自己的MAC地址后,发现它叫的不是自己,直接在数据链路层,将数据报文丢弃了而已
学习MAC报头
了解了MAC地址后,我们便可以看一下以太网的帧格式是如何的
图来自博主2021dragon
如何解包/交付
同样的,我们了解任何一个报头,都是从如何解包和向上交付说起
可以很直观的看出,以太网报头是一个定长报头,目的地址,源地址,类型,CRC四个字段加起来总共18个字节,直接分割,即可区分报头和有效载荷
那如何向上交付呢?我们知道网络层不一定用的是IP协议
答案是2个字节的帧类型字段
假如此时数据是IP报文,那对应填充为0800
PS:ARP,RARP都属于数据链路层,而不是网络层
假如此时数据是一个ARP报文,那对应填充0806
假如此时数据是一个RARP报文,那对应填充8035
具体过程
了解了MAC报头后,就可以具体细化我们上面讲述过的小故事了
现在在同一个局域网内,有很多台主机相连,包括我们的路由器也在其中
假如此时我们的主机A想要和主机E通信,则会发送对应的报文
对应的目的MAC地址填上E的,源目的MAC地址填上自己A的MAC地址即可
然后报文就会被发到网络当中,此时大家都会收到这个报文
不过大家都会对数据帧进行比对,看一下目的MAC地址和自己是不是一样,假如不一样,则网卡会直接舍弃对应的数据;假如一致,才会把对应的报文向上交付
那有没有办法,即便MAC地址不同,也会继续向上交付报文呢?
答案是有的!网卡中,可以被设置为混杂模式
设置为混杂模式后,主机就不会对报文的目标MAC地址进行认证,直接向上层交付,这也是我们大部分局域网抓包软件的原理
那我们说要对数据进行保护,是在数据链路层保护吗?
不是!而是我们之前提到过的应用层,对数据自己进行加密,这样别人获取到了,也无法对数据进行解读
假如此时主机A想要发送的数据对象不在这个局域网内,那目的端口MAC地址就填路由器的即可
数据碰撞
但是在一个局域网内,更多时候是多台主机相互发消息,但是这几台主机又是共享一个通信信道的,此时就会出现一个问题——数据相互干扰,更为专业一点的名词,我们称作为数据碰撞
在以太局域网中,任何时候,我们只能有一台主机在给另外一台主机发送数据帧,否则就会发送数据碰撞问题
那我们如何解决这个问题呢?
首先要有碰撞检测,也就是检测到数据的确发生了碰撞,出现了错误
所以我们会发现MAC报头里面有一个CRC字段,它就是用来解决这个问题的,A主机发消息,它自己也会收到,假如CRC校验不通过,说明此时数据发生了碰撞,反之,我们认为数据没有发生碰撞
检测到碰撞后,我们要进行碰撞避免
当主机发送出去的数据产生碰撞时,该主机需要等待一段时间后(sleep一下),再进行数据重发,这样就能够尽可能让局域网当中的数据消散
整体原则是什么?
其实就是采取碰一碰,试一试的策略
有人会说,这不会有点随意吗?
第一, 不要小看光速,实际数据碰撞的概率并不会很高
第二,它其实就是一种另类的重传机制而已,不仅仅TCP层有重传,我们的数据链路层也有!
第三,那我们还可以思考一个问题,数据相对越短,数据碰撞越少,还是相对越长,数据碰撞越少呢?
答案毋庸置疑,数据量一旦很长,横跨的时间段就会很大,一旦发生误码,TCP层会对整个数据进行重传,发生碰撞的概率就会进一步提高
因此我们数据量必须限制一定大小,这就是我们MTU的由来,上层交付的有效载荷不能超过1500字节
如何理解数据碰撞
那我们应该如何看待数据碰撞呢?
局域网在同一个时刻,只允许一台主机向另外一台主机发消息
有没有觉得很熟悉?
局域网的本质,在系统看来其实就是一个临界资源,一台台主机就相当于一个个进程,在同一时刻,我们只允许一个进程访问对应的临界资源
但是,我们说两者采取的策略不同,在系统中,我们采取加锁,信号量等方式;但是网络中采取的是直接试探
令牌环网其实就是如此,它存在一个称作令牌的东西,只有拿到令牌的人,才有资格发消息,拿我们之前的故事举例,只有拿到麦克风的人才有资格说话,其他人暂时闭嘴,令牌本质对应的就是我们系统中的互斥锁
所以,我们说系统和网络不分家,思想贯穿一致
还有一点需要说明
局域网中,主机数目越多,碰撞的概率也会相应增多
这也是为什么我们在大学上大课的时候,人一多,数据就比较难发出去,网络比较卡;或者学校操场校运会时也是如此
本质就是由于不断发生数据碰撞,一直在丢包的缘故!
PS:那假如我们要黑掉一个局域网,其中一个方法便是发送大量垃圾数据,增大数据碰撞概率
为了解决这个问题,对应设备便应运而生
我们称之为网桥,或者说交换机
它的作用就是划分碰撞域
假如我A主机和C主机通信,而不和B主机通信,此时就不用把对应的报文发给B,然后再判断后丢弃
交换机会将两者隔开,分成两个区域,相当于交流的双方有了自己的对话空间,从而减少数据碰撞的概率
假如A主机想要直接向路由器发消息,B主机所在区域也不再需要收到A主机报文,交换机会将报文转给路由器
ARP协议
我们说同一个局域网内,主机A向主机B发消息,在数据链路层会封装MAC帧,这意味着需要知道对方的IP地址
但是我们只知道对方的IP地址,在套接字socket编程的时候,也仅仅是提供对应的IP而已
那么如何根据对方的IP,得到对方的MAC地址,从而封装我们的MAC帧呢?
这就是我们ARP(Address Resolution Protocol,ARP)协议解决的问题.
它不是一个单纯的数据链路层的协议, 而是一个介于数据链路层和网络层之间的协议;
整体的框架如下图所示:
小故事
我们还是以我们之前的故事作为引入
现在老师同样要在班上点名回答问题,但是学校只发给老师对应学生的学号,而不是姓名
在老师点学生姓名回答问题之前,老师先要在班里大喊一句:“xxxx学号是哪位同学?你叫什么名字?”
对应的同学会站起来,然后回复老师自己的名字,比如说小明
老师知道他叫小明后,以后就能够通过直接叫小明,然后小明就会站起来回答问题了
同样的,学号其实就是我们的IP地址,姓名其实就相当于我们的MAC地址
在同一个局域网内,双方进行局域网通信之前,可以通过ARP协议,从对应的IP获取到对应的MAC地址
然后再进行局域网通信
协议格式
协议的整体格式如下图所示:
以太网目的地址/源地址
当想要获取对应接收端的MAC地址时,由于不知道对方的MAC地址,所以以太网的目的地址填充为FFFFFF,代表向整个局域网广播,对应以太网源地址填充上自己的MAC地址即可
当接收端给发送端对应的回应时,以太网MAC地址就可以填充上发送端的MAC地址,源地址此时填上自己接收端的MAC地址
这样一来一回,接收端便知道了目标主机的MAC地址
注意到源MAC地址、目的MAC地址在以太网首部和ARP请求中各出现一次,对于链路层为以太网的情况是多余的,但如果链路层是其它类型的网络则有可能是必要的.
帧类型
这在我们之前讲解封装时已经讲过
之前数据是IP报文,那对应填充为0800
但此时是ARP报文,则填充对应的0806
硬件类型/协议类型
硬件类型指链路层网络类型,1为以太网;
协议类型指要转换的地址类型,0x0800为IP地址;
硬件地址长度对于以太网地址为6字节;
协议地址长度对于和IP地址为4字节;
对于以太网中发送的ARP报文来说,这四个字段通常是固定的
OP字段
op字段为1表示ARP请求
op字段为2表示ARP应答
具体发送过程
了解协议格式后,我们便可以看一下具体发送过程是怎样的
假如此时我们的主机A依旧想要和主机E通信,不过在具体两者通信之前,还需要获取到对于主机E的MAC地址
于是A主机就会向局域网当中发送一个ARP报文
其中对于目的MAC地址,由于我们不知道,所以填充上对应的FFFFFF即可。代表广播
于是所有人都会收到对应的ARP报文,并进行对应的目的IP地址匹配,假如是自己,则可以填充对应的ARP报文返回给主机A;如果不是,则直接在ARP层将对应报文抛弃
返回的时候,就不用广播地址了,而是直接填上对应的MAC地址,毕竟我们收到对应的ARP报文,是已经知道对方的MAC地址的
此时的op也要从1改为2,代表应答报文
这是两台主机相互交换的情况,但是实际局域网内,是有很多台主机相互交换的
我们说一台主机,在局域网内部,不要有主人翁意识,大家都一样
任何一台主机都有可能向别人发起ARP请求,或者收到别人给你发的ARP请求
这也正是OP选项字段出现的必要性
所以,任何一台主机,在收到一个ARP报文时,优先看OP,再看对应的目的IP地址
假如OP是1,即这是一个请求报文
假如不是请求自己,直接在ARP层丢弃;
假如是请求自己,则构建对应的回应ARP报文返回
假如OP是2,即这是一个回复报文
假如不是请求自己,则直接在MAC帧层丢弃,根本不会往上交付给ARP层
假如是请求自己,才会向上交付给对应的ARP层
还有一个细节需要注意,ARP也是报文,所以经常发ARP报文询问对应的MAC地址,这样也同样可能导致数据碰撞
所以,不是每一次都要ARP,可以将IP地址与对应的MAC地址之间的映射,暂时缓存起来
我们可以在linux系统(windows)下,输入arp -a指令查看我们对应自己的IP地址和MAC地址映射
当然这种映射是有时间限制的,不然我们每次连wifi,路由器都会随机分配一个动态IP地址给我们,我们的IP地址是会发生改变的,此时映射之间就会发生错误
那有IP地址得到对应MAC地址的协议,有没有MAC地址得到IP地址的协议呢?
答案是有的!它就是我们前面提到过的RARP协议(R代表reverse逆转),也被称为逆地址解析协议,由于IP是直接就知道的,所以不难猜想,它的整个过程和我们的ARP协议类似,但是要简单很多.
ARP欺骗
在之前我们的HTTPS协议中,我们曾经提到过中间人盗取我们数据的知识,具体是怎么利用ARP成为中间人呢?
同样是我们的局域网,此时存在一个主机M,它想成为中间人的方法很简单
我们说有对应的ARP请求,就会给出对应的ARP回复
但是不妨碍没有请求时,也可以给出对应的ARP回复报文
主机M只要给对应的主机A构建假的ARP应答,告诉主机A,我是E主机,对应IP地址是IP E,MAC地址是MAC M
给对应的主机E构建假的ARP应答,告诉主机E,我是A主机,对应IP地址是IP A,MAC地址是MAC M
那在主机A和主机E数据交流时,它们以为双方都在和对面直接通信,但其实都经过主机M,这种做法在任何子网,公网都是可以存在的,因为IP地址是公开的.
同样的,我们说假如要使一个局域网暂时瘫痪,也可以发送无效的垃圾ARP报文,想要定向攻击一台主机,也可以发送大量错误的ARP应答等等.