引言:
北京时间:2024/3/14/9:20,简单聊一聊我的日常。昨天晚上十点左右更新完新的一篇文章,回到宿舍简简单单花了个两首歌的时间洗了个澡,然后为了保持形象吹了个头发,哈哈哈!当然对比以前的我我从来不吹头发。此时回想当年吕布确实勇猛。这都不是关键,关键是吹完头发喝两口热水咱就躺好睡觉去了,当然这个睡觉的勇气来源于我的眼罩以及耳塞加上我昨天为了更文没有午睡。可能是由于刚洗完澡不怎么好睡,有困意但是就是睡不着。隐约记得整个晚上都在想着子网划分都想着IP路由,反正早上起床第一感觉就是失眠很难受很难受。更可怕的是早八人本来应该八点的闹钟因为六点的闹钟忘记关了导致本就没睡好的我雪上加霜。不谈了,周末快要来啦!上个星期的周末没有好好利用居然跑去看电视了,不过确实是找到了一个还不错的电视叫《长相思》,还是那句话吕布不仅勇猛还抗揍。隐约记得我好想是在周六一天之内看了两部完整的电视剧,另一部没有达到我的预期我也就不说是啥了,当然《长相思》是后者,这剧后期剧情还紧凑搞得我追到了好几点。周天简简单单上了个早八,因此我睡了几个小时我不多说懂的都懂,但是莫名不困人这种生物确实很高级哦。下午自然是补觉直接睡到了六点好像,然后起来吃了个饭七七八八搞了一下,没记错的话九点多我就又已经重新躺好了,哈哈哈!快快乐乐简简单单周末过去了,不过一切的起因都是因为看了上周五也就是3月8号那场勇士和公牛的球赛。哎,本打算在图书馆认真码字的我就因为中午吃饭小看了一会,干!这场球赛我不多说,球赛是普通的球赛但是乱人心神也是真的乱人心神,然后下午五点回到宿舍准备小睡一会躺在床上自此不可自拔。在这个周末又会檫出怎样的火花捏!我不知道,但是我知道《与凤行》好像快要上映啦!作为资深的娱乐人士,快乐就完事。
回顾网络层相关知识
回顾的重要性不言而喻,所以养成好习惯每次都回顾。当然也算是补充部分遗漏知识。上篇博客我们重点对网络层相关知识进行了理解,对于IP协议以及很多原理可以说是非常明确。其中对于IP协议而言,从IP报头来看IP协议最重要的就是提供了分片重组以及路由选择的能力。当然也就是IP报头中16位标识、3位标志、13位片偏移字段以及32位源IP地址、32为目的IP地址字段提供的能力或者更准确的说是抓手。而当我们在学习IP协议是如何进行分片重组之时,我们还强调了为什么IP协议需要具有分片重组的能力,根据这个问题我们理解了有关MTU的相关知识,紧接着我们发现分片重组对于TCP协议而言容易造成数据传输效率降低、丢包率增高等问题。所以我们还进行了有关最大段尺寸或者说最大报文段长度(MSS)等知识的理解。而除了上述字段之外,我们知道IP报头中还具有部分用于处理特定场景或者说特定问题的字段,如4位版本类型、8位生存时间、8位协议、8位服务类型、16位首部校验以及4位首部长度、16位总长度。结合对路由选择或者说源IP地址和目的IP地址的认识我们明白了很多原理,而其中最重要的就是网段划分的原理。明确网段划分对于网络管理或者说IP地址管理具有重大影响。后针对网段划分我们意识到了IP地址数量限制问题,依次我们学习了CIRD策略、DHCP协议以及更加关键的NAT技术。了解了什么是私有IP和公网IP以及为什么的问题。明确了一个私有IP地址主机是如何通过NAT路由器将数据发送到公网以及NAT路由器如何进行应答数据的转发。但在上篇博客中对于NAT以及路由等知识还有部分需要补充,所以下述我们对路由以及NAT相关知识进行深入理解。
1.深入理解路由
之前由于没有深入学习有关数据链路层的知识,所以对于路由这块知识搞的比较混乱。我们明确对于路由器的路由而言,它关心的只是路由或者说路径选择或者说下一跳IP地址,而对于数据转发而言路由器或者说路由一点都不关心,它们只要根据下一跳IP地址调用对应的接口就行。所以对于路由器路由的具体过程我们可以这样理解,首先路由器根据IP协议对IP报文进行解包获取目的IP地址,其次根据路由表条目中不同子网IP地址的子网掩码和网络号对目的IP地址进行网络号匹配。也就是让目的IP地址与某子网IP地址的网络号对应的子网掩码进行按位与操作,若目的IP的网络号与该网络号匹配那么则表示我们找到了下一跳IP地址,接下来只要调用与该子网IP地址对应的接口,路由工作就全部完成。反之重复上述过程直到发生默认路由。因此对于路由而言我再强调一遍,它只关心路径选择至于路由转发中的转发指的只是调用某IP地址的接口而已。也就是说若是路由器与目的IP处于同一子网时,路由器进行路由转发也就是直接转发我们并不将其看成是一个路由过程,而只是一个数据转发过程或者说调用特定接口的过程。本质也就是路由器此时并没有发生查找路由表或者说路径选择。当然也就是说路由表上的IP地址一定是不同子网的IP地址,而不是同一子网的IP地址。而具体同一子网路由器需要如何进行数据转发这个问题,数据链路层会给你答案。最后对于路由表而言,由于不同的操作系统维护路由表的方式不同,所以部分字段可能有所不同,但是最关键的三个字段一定都需要有,当然这三个字段也就是不同子网的网络号和该网络号对应的子网掩码以及与子网IP地址对应的转发接口。如下图就是Windows系统维护的路由表,其中网络目标就是我们说的子网网络号,接口表示的就是对应子网IP地址,对于跃点数可以理解成是优先级。
2.再谈NAT,理解NAPT
通过上篇博客的学习,我们知道NAT路由器是NAT技术的硬件载体,NAT技术通过集成在NAT路由器上实现共享同一IP地址的能力。我们明确局域网私有IP地址是如何通过NAT技术不断进行IP地址替换,从而实现访问公网的过程。并且在上篇博客中我们同理说公网响应数据也是通过不断进行IP地址替换从而实现访问内网。现象如下图所示:当客户端A想要访问公网服务器时,NAT路由器需要转换IP报头中的源IP地址,也就是将客户端A的私有IP地址10.0.0.10转换为路由器的公网IP地址202.244.174.37。从而实现将IP报文发送到公网的同时具有接收响应数据的能力,也就是服务器可以根据路由器的IP地址或者说源IP地址来发送响应数据,而当NAT路由器收到响应数据时它知道这个数据不是给它的,它此时就又要对IP报头中的IP地址做替换,只不过此时它知道它要替换的不再是源IP,而是目的IP。所以它就将响应IP报头中的目的IP地址202.244.174.37替换成了客户端A的私有IP地址10.0.0.10,最后当目的IP替换完成NAT路由器就会进入下一步工作路由,从而实现将服务器应答数据成功响应给对应的客户端。
当然上图过程或者说上述过程,本质就是我们在上篇博客中谈到的有关一个路由器一般有多个LAN口IP,但只有一个WAN口IP,每次局域网主机想要向公网发送数据,都需要将源IP地址替换为WAN口IP,反之同理的过程。所以我们可以明确,由于WAN口IP只有一个,那么NAT路由器肯定不可能每次只处理一台主机数据,因此对于NAT路由器而言,它一定需要在其内部维护一张映射表,也就是对应主机私有IP地址与WAN口IP之间的映射表。每次在进行源IP地址替换时,都要将源IP地址与路由器公网IP地址或者更准确说是WAN口IP地址构建映射关系,从而实现准确快速的进行数据转发。回顾完上述知识,此时我们明确NAT路由器内部一定维护了一张地址转换表,但我们并不知道NAT路由器维护的这张表中具体有什么内容。所以我们通过一个场景来明确这张表中具体包含了那些信息。也就是在两台局域网主机同时访问同一台服务器时,如果NAT路由器只是简单的对不同的私有IP地址和目的IP地址进行维护,那么在目的IP地址相同的情况下,当NAT路由器接收到来自该服务器的应答数据时,NAT路由器就无法将该数据正确的转发到客户端主机上,也就是NAT路由器在查看自己维护的映射表时它会发现自己的WAN口IP地址和两台局域网主机的私有IP地址存在映射关系,此时NAT路由器就不能准确的判断出这份服务器应答数据应该发送给谁。因此为了解决这个问题,NAT路由器就需要再找一个抓手,也就是端口号。所以当NAT路由器在维护映射表时并不是只维护IP地址,如下图所示:
因此如上图中所示,NAT路由器在其内部维护了一张转换表,并且这张转换表不仅映射了私有IP地址与WAN口IP地址之间的关系,它还维护了对应IP地址与端口号之间的联系。因此也就可以说该转换表维护的是一个IP+PORT之间的关联关系,也就是上图中所示的10.0.0.1 : 1025与202.244.174.37 : 1025之间的关联关系。并且从上图转换表中我们还可以发现,该转换表除了维护IP+PORT之间的关联关系之外,它还维护了源IP+PORT和目的IP+PORT之间的关系。当然具体为什么要这么做,后续我们会说明。因此像上述转换表中所示,这种维护了私有IP+PORT和WAN口IP+PORT以及目的IP+PORT的转换表我们就将其称为是NAPT转换表。所以此时当NAT路由器维护了一张这样的NAPT转换表之后,上述场景不同局域网主机访问同一服务器导致应答数据转发不确定的问题我们就解决了。本质也就是此时NAT路由器的NAPT转换表中除了IP地址的映射之外,还有端口号的映射。当然这也就是为什么在上篇博客中我们说,NAT路由器在将私有IP替换成WAN口IP时,需要将端口号也进行替换。本质也就是在防止两台局域网主机的端口号相同的问题。因此基于对上述知识的理解,此时我们就可以明确两个点。首先对于NAT路由器而言,因为它不仅需要有替换IP地址的能力,它还需要有替换端口号的能力。所以我们明确NAT路由器与普通的路由器肯定不同,普通的路由器只能工作在网络层使用对应网络层协议,而NAT路由器除了能够使用网络层协议之外,它还可以使用传输层协议。当然这里我们用"使用协议"本质是我们将协议当作了一个可执行程序来看。其次我们从IP地址+端口号来看,在之前学习套接字时,我们说网络通信本质就是进程间通信。本质是因为我们可以使用IP地址+端口号的形式构建出一个全网唯一的进程。当然这个概念对于目前的我们而言是不怎么准确的,因为我们知道在不同的子网内是允许存在相同的私有IP地址的,注意: 此时我说的不同的子网指的是不同路由器构建的子网,因为只有不同路由器构建的子网才有可能会出现相同的IP。但站在NAT路由器的角度看,这个问题不是问题,就算此时可能存在多个相同的内网进程。只要NAT路由器在替换源IP地址和端口号或者说构建NAPT转换表时,在某端口号被使用了的前提下会替换端口号,那么一切问题就不是问题。因为我们本质也可以将WAN口IP和NAT路由器自己分配的端口号看做是一个进程。而只要NAT在分配端口号时不会分配到相同的端口号,因为WAN口IP是公网IP或者说是上一级网段IP,那么此时就不可能存在相同的进程。也就是说对于NAT路由器而言,它自己构建的进程一定是全网唯一的,因为它可以保证端口号一定不同。所以如果我们将局域网内可能相同的进程和NAT路由器自己认为永远不可能相同的进程构建一个NAPT转换表的映射关系,那么此时就可以保证这个映射关系是全网唯一的。当然本质还是因为NAT路由器自己的WAN口IP加端口号是全网唯一的且端口号是可变的。 所以我们明确对于NAT路由器而言,它通过不断的替换已经存在的端口,它就能构建出一张完全不同的K/V关系映射表,也就是NAPT转换表。当然上述只是一个假设过程,因为对于一台NAT路由器而言,它所包含的子网由于子网划分是不可能出现相同私有IP的。同理上述所说,想要在子网内构建出相同的私有IP,那么最少也需要两台路由器才行。最后明确,NAT路由器通过替换端口号和构建NAPT转换表,解决了在多个子网中存在相同私有IP地址时的通信问题。从而确保了每个连接在公网上的进程都有一个唯一的标识,从而实现了进程间的唯一通信。所以当我们明确了上述有关NAPT转换表相关的知识,此时我们就来回答最后一个问题也就是上述说过的为什么NAPT转换表需要维护目的IP和目的端口之间的映射,也就是上图转换表中所示,它不仅维护了10.0.0.1 : 1025与202.244.174.37 : 1025之间的关联关系,它还在该关联关系的基础之上维护了目的IP和目的端口,也就是10.0.0.1 : 1025加163.221.120.9 : 80与202.244.174.37 : 1025加163.221.120.9 : 80之间的映射。具体原因可能有很多,以下是我认为较为合理的原因。其一,虽然通过维护私有IP地址和端口与WAN口IP和端口号之间的关联关系足以实现数据包从内网到外网以及外网到内网的通信,这里我再强调与WAN口IP对应的端口一定是唯一的,因为当NAT路由器检测到私有IP对应的端口发生重复时,一定会将该端口给替换成一个没有被使用的端口。但是为了能够保证响应数据包回到内网主机的准确性,所以加上了目的IP地址和目的端口信息。其二,也就是我认为最合理的。维护目的IP地址和目的端口信息是为了提高对应子网的安全性。也就是说NAT路由器可以通过目的IP和目的端口检测外部响应数据包的源IP地址和源端口,从而根据NAPT转换表中有关信息判断该外部响应数据包是否安全,也就是是否符合我的NAPT转换表。只有当外部数据包的源IP地址和源端口符合NAPT转换表上对应的映射关系,此时我们才对该数据包进行接收。通过这样的手段来增加内网的安全性,防止未经授权的访问和攻击。本质反向推理也就是如果不维护目的IP和目的端口,当然强调此时是基于内网到外网发送的过程,也就是说目的IP和目的端口指的是服务器IP和端口。那么此时就会导致任意服务器可以直接通过WAN口IP肆无忌惮的访问内网中的主机,当然具体端口可以使用遍历。因此,尽管维护私有IP地址和端口号与WAN口IP和端口号之间的关联关系足以实现基本的数据包转发和接收,但为了确保数据包能够正确地回到内部网络中的目标设备,并提高安全性,NAT就需要维护目的IP地址和目的端口的信息。当然这种只有当内网访问了外网,也就是维护了NAPT转换表之后,外网才能向内网发送数据的方式本质也可以看做是NAT的一个缺陷。
相关拓展知识
当我们进一步了解了NAT技术,明确了NAPT转换表之后。我们会发现一个现象,只不过在阐述该现象之前此时我们先要明确一个注意点。我们要明白,并不是所有的路由器都是NAT路由器并不是所有的数据转发都需要维护NAPT转换表。也就是说对于路由器而言,它并不是每次进行数据转发它都要使用NAT技术,而是当路由器接收到一个数据包时,它首先完成的工作还是根据目的IP地址查找路由表。好比此时就只是简单的局域网内通信或者是公网通信,如果一个路由器能够在路由表中根据目的IP地址找到与其对应的网络号,那么我们就可以判断这个IP地址一定是一个局域网内的IP地址或者是一个公网IP地址,反正不管怎样这个目的IP地址一定不会越过当前子网,也就是当前路由器所包含的最大网段。因此路由器就可以直接路由而不需要使用NAT技术,更不需要维护NAPT转换表。而若是路由器发现自己的路由表无法与目的IP地址匹配,只能使用默认路由,那么此时路由器就需要使用NAT技术,也就是维护NAPT转换表。本质也就是因为默认路由会导致数据包出现在上一级网段中,超出当前路由器的管控范围,此时路由器就无法判断出该IP地址到底是一个私有IP地址还是公网IP地址,而为了能够接收到这个目的IP地址返回的数据,路由器就只能默默的维护一张NAPT转换表。因此对于一个数据包的路由过程此时我们就大致知道具体顺序了,首先根据IP地址查路由表,匹配直接转,反之则在默认路由前使用NAT技术维护NAPT转换表,最后默认路由。并且我们明确,由于内网主机正常情况下都有访问公网的需求,所以一般内网路由器都会集连NAT技术。并且我们要知道NAT技术本质是一种解决IP地址数量限制问题的技术,所以只在内网或者说局域网内适用,到了公网或者说到了运营商路由器或者说边缘路由器,NAT技术就不再适用。因此当我们明确了上述知识,此时无论是何种路由方式我们都欣然接受。而当我们对路由有了更深的认识之后,我们就来谈谈上述现象,我们会发现两台不同局域网内的主机无法直接通信,当然这里我特指的是两个跨多个网段的局域网。本质也就是只有两个跨多个网段的局域网之间才会存在多个路由器,才有可能会出现相同的私有IP。反之若是只通过一台路由器划分的子网,是不可能会存在相同的私有IP,还是那个观点想要实现私有IP重复最少需要两台路由器。而之所以这样的两个局域网之间不能直接通信,本质就是私有IP地址重复问题。所以此时我们能再次体会到NAT路由器保护子网安全的重要性。谈到这里我们就不得不谈谈我们日常使用的通信软件(微信)了。因为不同网段内的局域网因为私有IP地址的问题不支持通信,所以在当今这个客户端-服务端盛行的情况下,我们就可以利用公网服务器进行局域网通信。本质很简单,也就是内网主机可以通过NAT技术和NAPT转换表实现与公网服务器之间的交互。所以此时我们就会发现几个很有趣的现象,好比鸡生蛋还是蛋生鸡问题。若是内网主机不访问公网服务器,公网服务器就不能给你提供服务。好比你不下载微信客户端或者你不登录微信,你就无法与其它主机进行通信。好比别人给你发送了消息,由于你没有登入微信,微信服务器无法将这个消息转给你,你就无法看到别人发的消息。当然站在我们的角度理解,就是因为NAT路由器只有维护了特定的NAPT转换表,内网和公网之间才行进行正常的数据交互。水平不够这种现象我总结不出来,但是我觉得能够进一步理解,但是我理解不了。所以我们目前不管它,明白具体的原理就行。这里我们再谈一个有趣的现象,若是两台处于同一个子网下的主机或者说客户端或者说微信用户它们之间想要通信,其实这个过程不是内网到公网再公网到内网之间的数据转发,而是实实在在的局域网通信。当然局域网通信原理我们还没有学,但是我们只要知道它们之间的数据转发是通过子网路由器直接转发而不是通过公网服务器转发的。这个现象算是一种策略,虽然微信用户每次访问的目的IP地址都是微信服务器的IP地址,但是微信客户端可以根据特定的手段,如使用操作系统提供的底层网络功能的系统调用接口直接实现ARP广播等,具体很复杂我们不谈。我们只要明确在网络协议栈每一层都有相应的系统调用接口提供给上层使用,从而让上层可以根据具体的需求进行特定的网络操作。
正式学习数据链路层
在上述学习过程中,我们不断谈到转发以及局域网通信,此时我们就正式的来看看什么是转发,什么是局域网通信原理,当然这些知识肯定都属于数据链路层相关知识。在上述深入理解路由的过程中,我们说对于路由器的路由而言它关心的只是路径选择或者说下一跳IP地址,对于数据转发它并不关心。并且通过对网络层有关子网划分和IP的学习,我们知道路由器在进行跨网段传输时无论是默认路由还是特定IP地址转发,这个路由过程一定都是发生在同一个子网内或者说同一个局域网内。因此我们明确对于路由器的跨网段转发本质就是在不同的局域网中进行转发。而又因为路由器并不关心数据的转发,它只关心路径选择,所以在路由器跨网段转发中到底是谁在扮演数据转发的角色或者说数据转发的能力到底是由谁提供的呢?话不多说数据链路层说是我是我,当然之所以数据链路层具有数据转发的能力,本质还是因为数据链路层位于网卡驱动程序,拥有网卡提供的特定接口。所以我们明白一个数据之所以能够从一台主机发送到另一台主机,传输层提供传输策略(TCP),网络层提提供路径选择,数据链路层提供的才是数据转发。而又因为我们说数据转发本质就是在一个一个局域网内转发,因此对于网络层我们还可以理解成是为什么将数据从这个局域网转发到那个局域网而不是另一个局域网。而数据链路层提供的能力就是如何将数据从这个局域网转发到那个局域网。当我们有了上述认识之后,此时对于数据链路层的理解就是提供局域网内数据转发的能力。然而在我们正式理解局域网具体如何通信之前,我们需要对数据链路层中包含的三种不同局域网通信标准有一定的了解。当然之所以数据链路层需要有多种不同的局域网通信标准,本质就是因为这个世界存在多种不同的通信手段也就是多种不同的表示01的手段,如光电信号、无线电波等。也就是说底层物理层在设计网卡时因为表示01的方式有很多,所以存在网卡的类型就会不同。而因为网卡类型不同,此时提供给数据链路层使用的接口就不同,因此局域网内通信标准即不同。当然此时由于TCP/IP是分层结构,因此数据链路层的差异性对于上层而言可以通过特定的手段很好的兼容。而对于数据链路层中不同的局域网通信标准,其中以以太网和无线LAN最为常见。这两者最大的区别在于通信介质的不同,一个使用的是网线或者说光电信号一个使用的则是无线电波。因此它们之间的网卡肯定是不同的,也即是通信标准是不同的,当然也就是某些策略有所不同。当然具体在策略上有什么不同,我们需要以其中一个视角带入到局域网具体的通信过程中,因此此时我们就以以太网的角度来看看什么是局域网通信原理吧!
理解局域网通信原理
再次强调,网络数据传输本质就是路由器跨网段转发本质就是不断进行局域网通信,因此只要我们明白了一个子网内的通信原理,就等于明白了数据在整个网络的通信原理。在我们之前学习网络层时,我们一直在强调一个局域网内的任何一台主机都可以直接和另一台主机通信,不处于同一个局域网内的主机则需要使用路由器进行数据转发,这是为什么呢?本质这也就是局域网通信原理的前提。那是因为对于局域网而言,所有处于该局域网内的主机一定是通过直接连接或者共享同一个路由器来共享同一个网络。因此对于局域网内而言,我们就可以将其比喻成是一个班级。只要一个班级中的任何一个同学说话,班级中的所有人都可以听到,当然此时包括它自己。同理局域网通信,只要任何一台主机发送了报文,那么该局域网内的所有主机都将会收到这个报文。但收到归收到,如何处理归如何处理,所以并不是所有主机的处理方式都是一样的,只有特定主机会将该报文交付给上层。所以局域网内的主机如何知道这个报文是丢弃还是交付给上层呢?想要回答这个问题,此时我们就需要学习数据链路层中的一个关键协议MAC协议,当然同理对于协议而言,我们直接从该协议的示意图入手,如下图所示:
首先我们明确,上图是以太网通信标准中的MAC协议示意图,无线LAN目前的MAC协议我们不谈。从图中我们可以看出对于以太网帧也就是以太网MAC协议,它由目的MAC地址、源MAC地址、类型以及CRC字段构成。而其中对于MAC地址而言,我们可以看出它是用六个字节表示,类型用两个字节表示,CRC用四个字节表示,其中对于CRC而言我们就将其简单理解成是校验和用于检测MAC报文是否完整和准确。所以对于MAC协议而言,它肯定是使用定长的方式实现报头和有效载荷的分离。而具体如何向上层交付则有类型字段决定。所以对于类型字段而言,它一共有三种类型,其中0800表示IP数据报文类型、0806表示ARP请求/应答、8035表示RARP请求/应答。并且我们可以发现,对于IP数据报文类型而言,MAC协议或者说数据链路层规定其大小一般为46字节到1500字节,当然这也就是我们在网络层谈到的网络最大传输单元MTU。所以我们明白之所以数据链路层规定网络最大传输单元本质就是因为MAC协议规定,当然也就是网卡规定。当然具体网卡为什么要这么规定,后续我们深入局域网通信原理时再谈。而对于MAC协议的另外两种类型ARP类型与RARP类型,在我们正式开始学习ARP协议时我们再谈。并且我们能看出MAC协议要求有效载荷的最小值为46,所以若是该报文类型是一个ARP请求/应答或者是RARP请求/应答,那么则需要在补充18个字节的数据,而这种补充数据我们一般就称为是垃圾数据。明确上述有关MAC协议相关的知识之后,此时我们需要完成的工作是具体的看看局域网是如何进行通信的,也就是明确局域网内的主机是如何实现上述所说可以判断出一个数据应该丢弃还是交付给上层。最直接的方式就是通过示意图来讲解,所以如下局域网通信示意图所示:
从上图MAC报文我们可以看出,该MAC报文是A主机发送给D主机的。并且同理上述我们所说,由于局域网内的所有主机是通过直接连接或者共享路由器来共享网络的,所以当A主机发送数据给E主机时,局域网内所有主机的数据链路层都收到了同样的MAC报文。而当不同的主机收到了同样的MAC报文,此时它们首先就会对该报文进行报头和有效载荷的分离,然后读取报头中的目的MAC地址字段看该MAC地址是否与自己的MAC地址相同,若相同其就可以根据CRC字段以及类型字段,判断完该报文是否完整和准确后交互给上层网络层,反之则直接丢弃。所以根据上图中所示,此时就只有D主机会将该报文交付给上层,其余主机则是丢弃该报文。所以上述就是为什么局域网内的主机能够判断出一个报文应该丢弃还是交付,当然也就是我们所说的局域网通信原理。因此我们就能明白,为什么有的软件能够实现局域网抓包,原来前提就是因为所有的主机都能收到来自某一主机发送的数据,当然如果真的想要实现局域网抓包,则需要使用网卡或者说数据链路层中的特定接口实现,将网卡设置为混杂模式。当然将网卡设置为混在模式我们从原理上看,本质就是不对MAC报文的目的MAC地址进行匹配,直接向上交付。
理解局域网内的数据碰撞问题
当我们明确了上述有关局域网通信原理的知识之后,此时我们再来探讨一个问题,从而实现深入理解局域网通信原理。上述我们说局域网通信好比就是在一个班级里说话,除了你自己和与你说法的对象之外,整个班级里的人都能听到。那么此时问题就来了,假如此时班级里非常的吵闹,你说法时与你说法的对象还能听到或者说还能准确的听到吗?答案肯定是否定的,因此当一个局域网内所有主机都在发送数据时,此时就会导致数据之间互相干扰,而当被干扰数据被对端主机接收之后,此时就会导致CRC校验时判断出该数据不完整或者不准确,最终使得该数据被丢弃,发生局域网内的丢包现象。当然在以太网中数据具体如何被干扰我们不好理解,但是换个角度,我们以无线LAN来看,此时就非常清晰。好比每个主机都在发送无线电波,无线电波与无线电波之间就会发生干扰,导致波形改变。因此对于这种局域网主机互相干扰的现象我们就称为数据碰撞,而一个局域网也就被我们称为是一个碰撞域。有了问题自然就需要解决,所以站在以太网技术标准的角度,此时它就规定一个局域网或者说一个碰撞域任何时刻都只允许一台主机向另一台主机发送数据帧。那么问题就来了,如何实现局域网在任何时刻都只允许一台主机发送数据呢?所以以太网通信标准就规定每台主机都必须进行碰撞检测和碰撞避免。而其中对于碰撞检测而言,此时就是通过CRC校验判断一个MAC报文是否发生改变,若发生改变那么对应主机就认为是发生了数据碰撞,所以此时它就会执行碰撞避免机制。当然明确无论是那台主机发送数据,它都一定能收到自己发的数据,所以是对应主机自己对自己做碰撞检测。而对于碰撞避免机制,本质说好听点也就是等等再发或者说让其它主机先发,而对于我们的理解这就是一个阻塞过程,但当局域网内的大部分主机都发生阻塞,那么在我们看来这就是一个排队过程。因此通过这种碰撞检测和碰撞避免的机制,此时我们就可以实现局域网内任何时刻只有一台主机在发送数据。因此若是想要让整个局域网都无法上网,当然也就是无法发送数据。在我们明确了上述知识之后,原理则非常简单,本质也就是不断向该局域网内发送数据,也就是让局域网内的其它主机一直认为发生了数据碰撞,从而一直阻塞一直排队。当然由于我们也属于局域网内的一台主机,所以我们自身肯定也会发生碰撞检测和碰撞避免。因此若是真正想要实现这个想法,我们需要克服的问题就是如何将碰撞避免机制给关闭,因为碰撞避免本身就是以太网数据链路层上的一种策略。所以在应用层想要实现上述所说我们就可以通过某些工具,绕过以太网驱动程序,从而实现关闭碰撞避免机制。当然值得注意的是,以太网数据链路层的这种碰撞检测机制其本身就是一个丢包重传机制,所以我们明白并不是只有TCP能够发生丢包重传,局域网内也可以发生丢包重传。最后明确,结合我们之前对线程相关知识的学习,我们就可以将局域网理解成是一个局域网内主机的共享资源,通过实现碰撞检测和碰撞避免来对该共享资源进行保护。而对于局域网任何时刻只能有一台主机发送数据,我们也可以将局域网看成是一个临界资源,每次都只能有一个线程进行访问。当然对于无线LAN和令牌环这两个技术标准而言,它们也有属于自己的策略来解决局域网数据碰撞问题,无线LAN策略和以太网大致一样,但对于令牌环而言我们应该非常熟,好比令牌环之所以叫令牌环本质就是因为只有拥有令牌的局域网主机可以发送数据,这不就是我们在学习线程时学习的互斥锁原理吗?
理解局域网交换机问题
通过对上述有关知识的理解,此时我们明白一个局域网就是一个碰撞域,为了解决数据碰撞问题以太网通信标准采用了碰撞检测和碰撞避免来实现局域网内任何时刻都只能有一台主机发送数据。明白了这些之后,那么此时我们就有两个问题,那么一个局域网内主机数是越多越好,还是越少越好呢?以及在局域网内主机一次发送的数据是越大越好还是越小越好呢?当然明确,无论是越多还是越少还是越大还是越小都是在合理范围之内。首先对于第一个问题而言,答案肯定是后者。因为若是当一个局域网内的主机数量非常多的话,就会导致碰撞域的碰撞概率增加,也就是局域网内主机一直会发生碰撞避免也就是一直被阻塞。所以为了提高一个局域网内的通信质量,方法有很多,其中最简单的就是控制局域网内主机的数量,但这个方法在大多数场景并不适用,如学校或者公司这样的一个局域网肯定会存在大量的主机。因此解决一个局域网内主机数量有限的问题,最好的方法就是使用交换机。所以我们此时就知道为什么局域网需要有交换机或者说网桥了吧!从碰撞域的角度来看,交换机所起的作用就是分割碰撞域,也就是将局域网内的主机通过多个交换机分割成不同的子区域。当然这个场景就非常像是我们在进行子网划分的时候,用路由器将不同的主机划分成不同的子网。只不过此时已经是在某子网也就是局域网内部,所以我们只能将其称为子区域而不是不同的子网。当然对于交换机具体如何实现分割碰撞域或者说如何实现局域网内的数据转发,我们都不关心,明白所以然就行。我们只要明确当局域网内有了交换机的概念之后,主机之间发送数据面临的干扰和冲突就会减少,从而大幅度提高数据传输的效率。也就是说交换机的核心工作应该是分割碰撞域,其次才是进行数据转发。当然根据上述所说这也就是为什么对于一个家庭而言,没有交换机的说法只有路由器的说法了。对于另一个问题而言,答案肯定也是后者。这里也就是网卡需要限制MAC帧报文大小的核心原因。同理如果你每次发送的报文都非常大,也就是该数据在局域网内转发的时间较长,那么依然会导致数据碰撞的概率增加阻塞时间变长。并且由于以太网通信标准使用的是碰撞检测机制,也就是我们上述说的数据重传机制,想都不用想数据越大重传成本当然越高。因此主机网卡在发送数据或者说在局域网内发送数据时,就一定需要控制发送数据的大小,也就是控制数据链路层对MAC帧封装的大小。当然解决的其实也就是我们之前在网络层说需要控制MTU的原因降低延迟。
理解ARP协议
行文来到这里,局域网通信原理我们算是有一定认识了。结合对MAC协议的认识,我们知道局域网内主机之间的通信是通过MAC协议来完成的。也就是局域网内的一台主机想要给另一台主机发送数据,此时就一定需要知道对端主机的MAC地址,也就是MAC协议中的目的MAC地址。那么此时问题就来了,你说数据链路层想要通信就必须知道对端主机的MAC地址,但是网络层又说想要实现通信就必须知道对端的IP地址。那么此时到底是用IP地址还是用MAC地址呢?当然很简单啊!谁是上层不就听谁的吗?因此对于网络层而言它只认IP地址,你想要和谁通信我不管我只要IP地址。所以当局域网内的一台主机想要给另一台主机发送数据,此时就必须知道它的IP地址。好啊,孩子你还挺有个性不是,此时应用层就乖乖的将目标主机的IP地址告诉了网络层。当网络层知道了目的IP之后,它就说哈哈哈,终于轮到我来当老大了,数据链路层你过来,帮我们把这份报文交给这个IP的主机。而当数据链路层看到一个四个字节的东西,它说老大啊,这是什么鬼东西啊,我怎么不认识啊!网络层此时就说你个没用的东西,随即把ARP叫了过来。当ARP屁颠屁颠的跑过来之后,网络层就说ARP啊你想办法让数据链路层这个呆子可以成功的将这份报文发出去。因此此时我们就可以明确,在网络层和数据链路层之间存在一个桥梁叫做ARP协议。对于ARP协议到底处于那一层的问题我们不关心因为这个问题毫无意义,我们关心的是ARP的桥梁地位或者说ARP所起的作用。所以ARP协议到底在网络层和数据链路层起什么样的作用,有什么样的地位。此时我们首先就来看看ARP的协议示意图,如下所示:
在上述我们学习MAC帧协议的时候,我们就知道0806帧类型表示的就是ARP请求/应答的MAC报文。其中有效载荷也就是ARP请求/应答一共28字节,因此对于ARP协议而言它一共就是28字节。其中硬件类型占两字节,其表示的意思是物理地址类型,其一般被置为1表示MAC地址类型或者说该APR协议此时是提供给MAC帧协议使用。因此无论是以太网通信标准还是无线LAN通信标准这个值都是1。协议类型也占两个字节,其表示的意思为该ARP协议此时映射的地址类型,而因为我们使用ARP协议解决的就是MAC地址和IP地址的映射或者说转换,因此协议类型表示的就是IP地址类型,一般被置为0x0800。所以我们能意识到ARP协议除了支持MAC地址和IP地址之间的映射,它也可以帮助其它硬件地址和协议地址进行映射或者说转换。并且我们还能意识到,因为ARP协议在我们眼里就只是完成IP地址和MAC地址的转换,所以这两个字段对于我们而言就是固定用法。而硬件地址长度和协议地址长度表示的也就是对应硬件类型和协议类型表示地址的长度,MAC地址为6,IP地址为4。最后一个也是最为关键的一个OP其也占用两个字节,表示的意思就是该ARP报文此时是请求报文还是响应报文,当然也就是说明ARP请求和ARP响应之间的处理动作不同,其中1表示ARP请求,2表示ARP应答。当然剩余字段顾名思义,最终所有字段加起来刚好等于28字节。只不过值得注意的是,此时对于0806类型的以太网MAC帧报文而言,它就同时具有两个目的MAC地址和源MAC地址字段。这个现象并不是说ARP协议中的目的MAC地址和源MAC地址冗余,可能只是以太网MAC协议用不上,但是其它局域网通信标准的MAC协议需要使用。所以我们也就明确,虽然数据链路层存在着各种不同的通信标准,但在网络层看来它们获取MAC地址的方式都是一样的,上层通过特定的机制此时也就是ARP协议屏蔽了数据链路层通信标准之间的差异性,从而成功实现IP地址到MAC地址的转换。当我们明白了上述有关ARP协议示意图相关知识,此时我们就正式来看一看在局域网内是如何进行IP地址到MAC地址的转换,如下图所示:
在具体明确局域网内IP地址到MAC地址的转换之前,此时我们再强调一下一台主机是如何发送数据的。明确当一台主机在发送数据时,应用层一定需要提供一个IP地址,这个IP地址可以是局域网内主机的,也可以不是局域网内主机的。当网络层获取到目的IP地址,它首先会根据当前局域网的子网掩码对目的IP地址和自己的IP地址做按位与操作,然后判断目的IP地址的网络号和自己的网络号或者说该局域网的网络号是否相同,若相同则同理局域网通信原理,若不同此时则需要进行查找路由表的操作。而一般对于一台局域网主机而言,它只有一张网卡也就是它一般只属于该局域网也就是不会同时存在于其它子网,因此对于查找路由表的操作我们可以理解为就是在默认路由,也就是在明确该子网出口路由器的IP地址。当明确了出口路由器也就是默认路由的IP地址之后,那么由于出口路由器此时也属于该局域网,因此照样同理局域网通信原理,也就是接下来我们要重点介绍的ARP协议。所以我们知道,当网络层通过目的IP地址明确了下一跳的IP地址之后,此时它就要让数据链路层帮它将数据转发给下一跳IP地址对应的主机或者路由器,但由于数据链路层只认MAC地址不认IP地址,所以网络层就需要实行特定的策略将IP地址转换为MAC地址,更准确的说应该不是将IP地址转换为MAC地址,应该是通过IP地址获取到MAC地址。因此在网络层中ARP协议就诞生了。结合对ARP协议的认识,如上图所示我们就自己封装了一个ARP报文。在主机A想要与主机D通信的场景之下,我们明确主机A一定知道主机D的IP地址(应用层获取),主机A此时根据原理发现目的IP地址与自己属于同一个局域网,此时主机A的网络层首先会检测本地的ARP缓存,若是其中有目的IP地址对应的MAC地址,那么它就直接将该MAC地址提供给数据链路层用于封装0800类型的MAC报文,最终成功将数据发送给主机D。而若是检测本地ARP缓存并没有发现主机D的MAC地址,那么此时网络层就需要依据ARP协议封装ARP报文,然后将ARP报文提供给数据链路层用于封装0806类型的ARP请求/应答MAC报文。而根据我们对ARP协议的认识,我们就可以将ARP封装成上图中所示。唯一值得注意的是,因为此时我们并不知道主机D的MAC地址也就是目的MAC地址,所以我们需要使用FFFFFF表示占位符。当然我特指的是如上图所示没有交换机的局域网,如果一个局域网内有交换机那么另当别论。同理当数据链路层收到ARP报文之后,对其封装时一样要将目的MAC地址设置为FFFFFF用于占位。所以当局域网内的所有主机都收到该ARP请求类型的MAC报文时,同理局域网通信原理中所说,所有主机都会对其进行报头和有效载荷的分离。而因为数据链路层将FFFFFF设置为了一个特殊标识,所以当局域网内的主机发现自己的MAC地址和目的MAC地址不同此时也不会将该报文丢弃,而是交付给上层。而当网络层收到了对应的ARP请求报文,由于它自己并不知道这个ARP报文是请求报文还是响应报文,所以它第一步操作就是提取ARP报文中的OP字段,若OP为1此时进行的动作则是判断目的IP,若发现目的IP地址与自己的IP地址不同,则将该ARP报文丢弃,若相同那么此时就需要构建ARP响应。而对于构建ARP响应而言,本质也就是对源MAC,源IP,目的MAC,目的IP字段进行填充,但不同的是构建ARP请求报文时对应网络层不知道目标主机的MAC地址,但是在构建ARP响应时此时对应网络层就知道目标主机的MAC地址了。所以当ARP响应构建完成,当然OP从1变成了2,网络层同理将其提供给数据链路层构建0806类型的ARP请求/应答MAC报文。只不过此时数据链路层在封装MAC报文时同理其也就知道了目的MAC地址。因此当主机D将响应报文发送,同理局域网通信原理,此时所有主机实现报头和有效载荷的分离,判断目的MAC地址与自己的MAC地址,此时就可以发现只有主机A能够成功匹配。同理主机A交互给网络层,网络层判断OP,发送OP为2,执行ARP响应报文对应的动作,提取源MAC地址。最终主机A就知道了主机D的MAC地址。当一台主机有了目的MAC地址之后,多的我不说同理。而当我们明确了具体是如何通过IP地址获取到MAC地址之后,局域网通信我们就打通了。让后结合目的IP地址到底是局域网内的还是不是局域网内的,也就是到底要不要进行默认路由或者说到底要不要根据路由器的IP地址获取路由器的MAC地址。一切的一切我们就明白了。也就是假如此时就是在默认路由,根据上述原理成功拿到了出口路由器的MAC地址,成功的将数据转发给了路由器,那么对于路由器而言,此时不就同理网络层路由的知识吗?不就是查找路由表,找到下一跳IP地址,而当找到下一跳IP地址之后,不还是在进行上述所说的局域网通信吗?说到底一切的一切不还是IP地址,一切的一切不还是子网划分。也就是说搞清了网络层相关知识,明确了什么是ARP协议,网络通信原理没有痛点。上述我们谈的简单的局域网也就是没有交换机的局域网,而对于有交换机的局域网,那么对于FFFFFF而言此时就不再是单纯的占位以及标识,其此时表示的就是货真价实的广播地址。也就是说只有当交换机识别到FFFFFF才会将对应数据包也就是ARP请求/响应类型的MAC报文广播给局域网内所有主机对应的端口。本质也就是说如果一个局域网内有了交换机,那么该局域网内主机发送的数据就不会再如上图中所示简简单单的就发送给了所有主机,换个角度也就是局域网内主机发送的数据优先被交换机接收。并且理解了上述知识,此时我们能发现,一个数据想要实现跨网段传输或者说跨局域网传输,那么源MAC地址和目的MAC地址一定是在不断变化的。因此通过这点我们再次明确为什么上层能够屏蔽数据链路层不同的技术标准。最最后我们明白,在局域网内发送一个ARP请求效率是非常低的,所以如上述所说网络层一定会维护一张ARP映射表或者说ARP缓存。
拓展:如何通过ARP成为中间人
当我们明确了上述有关ARP协议的知识之后,此时我们就来看看如果使用ARP成为中间人吧!当然对于什么是中间人,当初我们在学习HTTPS协议时,就是通过中间人的概念来强调HTTPS协议中CA证书或者说证书认证的重要性。因为若是没有证书,中间人就可以在客户端和服务端建立连接的过程中将通信秘钥窃取,所以为了保证网络通信的安全性,HTTPS就必须采取证书认证的策略。而虽然HTTPS使用该策略避免了中间人的问题,但是并不是说中间人就没有作用了。毕竟并不是所有的网络数据传输协议都是HTTPS协议,所以中间人依据可能可以窃取用户数据。所以接下来我们就来看看使用ARP如何成为中间人,首先我们明确,想要使用ARP成为中间人那么就一定要处于对应局域网内,其次就是获取该局域网内路由器的IP地址。因此原理就是,通过不断给目标主机发送ARP应答,当然此时的ARP应答中源MAC地址为中间人MAC地址,而IP地址为路由器IP地址。当然前提你知道目标主机的IP地址和MAC地址。也就是让目标主机误以为我是路由器,将要发送给路由器的数据根据MAC地址先发送给我,从而实现窃取数据或者说服务器公钥,然后同理中间人自己的策略,修改公钥为自己的公钥,然后再将数据默认路由发送给路由器,最后当路由器收到客户端响应数据或者说客户端使用对称加密解密算法生成的唯一秘钥,同理就转给了中间人。最后同理中间人冒充路由器将数据返回给目标主机。因此上述过程也被称为ARP欺骗。同理上述原理,如果我们直接拿着路由器的IP地址不断给目标主机发送ARP应答,那么就可以让目标主机无法上网或者说窃取目标主机的数据。