自上而下的理解网络(5)——IP篇
本系列博客到此,在理解网络这一专题中,我们已经走过了不短的路程。你或许已经发现了,由于网络分层模型的存在,每一层都有明确的任务和目的,使得每一层的工作都不太复杂,上层也不需关心下层的实现方式,整个网络结构有了更强的灵活性与扩展性。在上一篇中,我们介绍了TCP协议,这种可靠的传输协议保证了将应用层的数据准确无误的传输到目的端。从网络模型上看,TCP属性传输层的协议,传输层的TCP协议数据最终会被组成成IP数据报,开始进入真正的数据发送。本篇文章,我们将进入网络世界最核心的部分:网络层。对IP协议进行介绍。
一.谈谈IP协议
IP是一种定义了网络之间如何互联的协议,是TCP/IP协议簇中的核心协议。和传输层的TCP协议相比,IP协议的最大特点是不可靠且无连接。所谓不可靠,是指IP协议并不能保证IP数据报可以成功的到达目的端,数据传输中间发生任何错误,此数据报都会被丢弃掉。无连接是指IP并不会维护任何与数据报相关的连接信息,每次数据传输都是独立的,每个数据报的路由选择也都是独立的,因此IP数据报的到达顺序也是无序的。
首先,我们可以先随便看一个网络通信过程中IP层的数据报样子,如下图所示:
我们知道,在网络模型各层中,下层协议将上层数据拿到,并且拼接上本层协议头部信息作为完整数据报传递再传递给更下层处理。上图示例的即是IP层数据头的部分字段。可以看到,我们平时使用HTTP/HTTPS等应用层协议来进行通信时,是根据域名中的路径来处理业务逻辑的,而之下的TCP协议又是根据端口号来区分应用的,到了IP协议这一层,已经没有任何域名和端口号的概念,其提供的就是端到端的网络通信功能。
1.IP数据报的头部组成
IP协议的结构定义如下图所示:
可以看到,对于IP数据报来说,如果其首部没有特殊的配置选项,则其固定为20个字节长度。
第0到3位:标记了所使用的IP协议的版本,如果使用的是ipv4版本则此值为4,如果使用的是ipv6版本,则此值是6。
第4到7位:记录了IP数据报头部的长度为多少个32位的数据。
第8到15位:标记了服务的类型,会表明最小时延和最大吞吐量信息。
第16到31位:这16位数据记录了标记了整个IP数据报的总长度(字节),包括头信息和数据信息,由于其只有16位,因此其最大值为65535,一个IP数据报最大的长度为65535字节。
第32到47位:此16位数据是一个作用类似与id的标识字段,当发生了数据报分段时,此字段的值被复制到所有的分段之中,帮助接收端集中处理。
第48到50位:这3位是3个标记位,其中第1位是保留位,目前没有使用。第2位表示数据报是否可以进行分段,如果设置为1表示机器不能将此数据报进行分段。最后1位表示当前数据报是否是最后一个分段,如果存在下一个分段,则此位设置为1,否则设置为0。
第51到63位:这13位指出了分段数据在源数据报中的相对位置,如果没有分段,则此值为0。
第64到71位:生存时间字段,这个字段是一个简单的计数器,表明了数据报可以经过的最多路有数,数据报一旦经过一个路由器的处理,此值就会减少1,当值为0时,此数据报会被丢弃。
第72到79位:此字段指出了IP处理完数据后,使用什么协议来解析数据,其取值范围为0到255之间,其中常见的如1为ICMP空值协议,6为TCP协议,17为UDP协议等。
第80到95位:这个字段为投不校验和字段,占有16位,用来验证IP数据报头部的完整性。
第96到127位:这32位数据记录了源主机的IP地址。
第128位到159位:这32位数据记录了目标主机IP地址。
需要注意,上面的分析是以ipv4版本为例的,对于ipv6协议,头信息的字段意义会有一些变动,例如其源地址和目的地址都扩展为了128位。
2.IP路由选择的策略
了解了IP数据报组成的基本情况,下面我们该来思考下具体网络通信的实现方式了。这就会涉及到IP路由选择的相关内容。其实,IP路由选择并没想象的那么复杂,虽然世界上网络本身错综复杂。我们可以这样来思考:任何一台设备要接入网络,都要由链路层真正的连接进网络中,以个人PC为例,一定要使用有线或无线的方式接入到互联网中,我们才能与这台PC通信。因此,如果目的主机与源主机是直接相连的,则IP数据报会从源主机直接发送到目的主机上,这没有任何难以理解的地方。略微复杂一些的地方在于,如果源主机与目的主机不是直接相连的,则此IP数据报需要做选路逻辑,简述其过程如下:
1. 源主机搜索本地路由表,寻找目的IP所在的网络,如果找到就发送给此网络,没有找到会发送给路由表配置的default地址。
2. 接收到IP数据报的设备可能是一台主机,也可能是路由器设备(其实主机也可以配置路由器功能),其首先会判断IP数据报中的目的地址是否是本机IP或者是广播地址,如果是,则解析数据报进行处理,如果不是,则表明此数据报需要被转发。如果当前设备是普通的主机,没有路由功能,则此数据报会直接被丢弃。如果当前接收的设备是路由器,则会搜索自己的路由表,执行与过程1类似的行动,将数据报转发出去。当前,转发前其也会检查数据报的生存时间是否正常。
3. 下一跳的接收设备按照步骤2进行重复,直到数据到达目的主机,或转发次数超出数据报生存时间。
上面有提到路由表,路由表是IP层维护的一份路由信息,路由表中的每一项记录都包含4个字段,分别为:
目的IP地址:此项即可以是一个完整的主机地址,也可以是一个网络地址。
下一跳IP地址:数据要被转发到的地址。
标志字段:指定此条记录中的目的IP地址是网络地址还是主机地址。也用来指明下一跳IP地址是一个路由器还是一个直接相连的接口。
传输指定的网络接口:传输数据报指定的网络接口。
如果你使用的Mac电脑,则可以在终端输入如下命令来打印本机路由表:
netstat -nr
输出信息示例如下:
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.1.1 UGScg en0
10.8/24 10.8.0.2 UGSc utun0
10.8.0.2 10.8.0.1 UH utun0
127 127.0.0.1 UCS lo0
127.0.0.1 127.0.0.1 UH lo0
169.254 link#6 UCS en0 !
192.168.1 link#6 UCS en0 !
192.168.1.1/32 link#6 UCS en0 !
192.168.1.1 8c:73:a0:ef:e8:11 UHLWIir en0 1174
192.168.1.3/32 link#6 UCS en0 !
192.168.1.3 88:66:5a:b:69:2b UHLWI lo0
224.0.0/4 link#6 UmCS en0 !
224.0.0.251 1:0:5e:0:0:fb UHmLWI en0
239.255.255.250 1:0:5e:7f:ff:fa UHmLWI en0
255.255.255.255/32 link#6 UCS en0 !
Internet6:
Destination Gateway Flags Netif Expire
default fe80::1%en0 UGcg en0
default fe80::%utun1 UGcIg utun1
default fe80::%utun2 UGcIg utun2
default fe80::%utun3 UGcIg utun3
default fe80::%utun4 UGcIg utun4
default fe80::%utun5 UGcIg utun5
default fe80::%utun6 UGcIg utun6
::1 ::1 UHL lo0
2409:8a1e:2147:e770::/64 link#6 UC en0
2409:8a1e:2147:e770:1e:db2d:96a4:cf35 88:66:5a:b:69:2b UHL lo0
2409:8a1e:2147:e770:a823:bf83:873f:1241 88:66:5a:b:69:2b UHL lo0
fe80::%lo0/64 fe80::1%lo0 UcI lo0
fe80::1%lo0 link#1 UHLI lo0
fe80::%en5/64 link#4 UCI en5
fe80::aede:48ff:fe00:1122%en5 ac:de:48:0:11:22 UHLI lo0
fe80::aede:48ff:fe33:4455%en5 ac:de:48:33:44:55 UHLWIi en5
fe80::%en0/64 link#6 UCI en0
fe80::1%en0 8c:73:a0:ef:e8:11 UHLWIir en0
fe80::1cb4:b83d:af72:eebe%en0 88:66:5a:b:69:2b UHLI lo0
fe80::%awdl0/64 link#7 UCI awdl0
fe80::7c27:deff:fe56:fc75%awdl0 7e:27:de:56:fc:75 UHLI lo0
fe80::%llw0/64 link#9 UCI llw0
fe80::7c27:deff:fe56:fc75%llw0 7e:27:de:56:fc:75 UHLI lo0
fe80::%utun1/64 fe80::1f51:69aa:bba3:107%utun1 UcI utun1
fe80::1f51:69aa:bba3:107%utun1 link#15 UHLI lo0
fe80::%utun2/64 fe80::d0d1:ddd2:5699:a7eb%utun2 UcI utun2
fe80::d0d1:ddd2:5699:a7eb%utun2 link#16 UHLI lo0
fe80::%utun3/64 fe80::24c9:ab2d:b06c:ee2b%utun3 UcI utun3
fe80::24c9:ab2d:b06c:ee2b%utun3 link#17 UHLI lo0
fe80::%utun4/64 fe80::aa3:5b6:85:9502%utun4 UcI utun4
fe80::aa3:5b6:85:9502%utun4 link#18 UHLI lo0
fe80::%utun5/64 fe80::383a:6846:f4a5:7d30%utun5 UcI utun5
fe80::383a:6846:f4a5:7d30%utun5 link#20 UHLI lo0
fe80::%utun6/64 fe80::7017:7a51:2293:202%utun6 UcI utun6
fe80::7017:7a51:2293:202%utun6 link#21 UHLI lo0
ff00::/8 ::1 UmCI lo0
ff00::/8 link#4 UmCI en5
ff00::/8 link#6 UmCI en0
ff00::/8 link#7 UmCI awdl0
ff00::/8 link#9 UmCI llw0
ff00::/8 fe80::1f51:69aa:bba3:107%utun1 UmCI utun1
ff00::/8 fe80::d0d1:ddd2:5699:a7eb%utun2 UmCI utun2
ff00::/8 fe80::24c9:ab2d:b06c:ee2b%utun3 UmCI utun3
ff00::/8 fe80::aa3:5b6:85:9502%utun4 UmCI utun4
ff00::/8 fe80::383a:6846:f4a5:7d30%utun5 UmCI utun5
ff00::/8 fe80::7017:7a51:2293:202%utun6 UmCI utun6
ff01::%lo0/32 ::1 UmCI lo0
ff01::%en5/32 link#4 UmCI en5
ff01::%en0/32 link#6 UmCI en0
ff01::%awdl0/32 link#7 UmCI awdl0
ff01::%llw0/32 link#9 UmCI llw0
ff01::%utun1/32 fe80::1f51:69aa:bba3:107%utun1 UmCI utun1
ff01::%utun2/32 fe80::d0d1:ddd2:5699:a7eb%utun2 UmCI utun2
ff01::%utun3/32 fe80::24c9:ab2d:b06c:ee2b%utun3 UmCI utun3
ff01::%utun4/32 fe80::aa3:5b6:85:9502%utun4 UmCI utun4
ff01::%utun5/32 fe80::383a:6846:f4a5:7d30%utun5 UmCI utun5
ff01::%utun6/32 fe80::7017:7a51:2293:202%utun6 UmCI utun6
ff02::%lo0/32 ::1 UmCI lo0
ff02::%en5/32 link#4 UmCI en5
ff02::%en0/32 link#6 UmCI en0
ff02::%awdl0/32 link#7 UmCI awdl0
ff02::%llw0/32 link#9 UmCI llw0
ff02::%utun1/32 fe80::1f51:69aa:bba3:107%utun1 UmCI utun1
ff02::%utun2/32 fe80::d0d1:ddd2:5699:a7eb%utun2 UmCI utun2
ff02::%utun3/32 fe80::24c9:ab2d:b06c:ee2b%utun3 UmCI utun3
ff02::%utun4/32 fe80::aa3:5b6:85:9502%utun4 UmCI utun4
ff02::%utun5/32 fe80::383a:6846:f4a5:7d30%utun5 UmCI utun5
ff02::%utun6/32 fe80::7017:7a51:2293:202%utun6 UmCI utun6
上面的路由表中包含了ipv4和ipv6的路由记录,我们先只关心ipv4的。可以看到,第一条记录的目的地址及是default,我当前设备上几乎所有的网络通信都会命中这条路由信息,其对应的下一跳地址为192.168.1.1,这正是我路由器的地址,因此可以看到,对于个人电脑,网络的访问大都是通过路由器完成的转发(与网线直连的设备这里会有不同)。
对于路由表中的Flags字段,我们还可以再深入的了解一下,其共有5种标记可以配置,且可以聚合,标记列举如下:
U:此标记表示该条路由记录可用。
G:表示该路由连接的是一个网关(路由器),如果没有该标记,则表示是直连。
H:表示该路由的目的地址是一个主机。如果没有该标记,表示目的地址是一个网络。
D:表示该路由是由重定向报文创建的。
M:表示该路由被重定向报文创建。
从路由转发的方式上我们也可以明白,IP的路由选择是逐跳进行的,无论是再哪个过程设备上,IP层都是无法知道完整的路由路径的(除非是源主机与目的主机直连的)。在IP数据报转发时,我们只能认定下一站路由是比当前主机更加接近目的主机的。
3.关于IP编码
现在,我们再来一起回顾下IP地址的编码方式。首先,我们此次讨论的都是ipv4,,每个IP地址都包含网络号和主机号,同一个网络上的所有主机网络号都相同。为了方便适配不同容量的网络,IP地址被分为了5类。
A类:IP地址范围从1.0.0.1 - 127.255.255.254
对于A类地址来说,第一段号码为网络后,其后三个号段为主机号,因此其可分配的网络数非常少,只有126个,每个网络可以分配的主机数非常多,有16777214个。
B类:IP地址范围从128.0.0.1 - 191.255.255.254
B类地址的前两段为网络号,后两段为主机号。B类地址可以分配16384个网络,每个网络可以分配65534个主机。
C类:IP地址范围从192.0.0.1 - 223.255.255.254
C类地址中前三段为网络号,最后一段为主机号,因此其可以分配的网络数为2097152个,每个网络可以分配的主机个数为254台。
D类:IP地址范围从224.0.0.0 - 239.255.255.255
D类IP地址为组播地址。
E类:IP地址范围为240.0.0.0 - 255.255.255.255
此类为保留地址,留待特殊用途。
如果你在百度中输入IP地址,可以看到当前电脑所接入的网络被分配的IP,如下图所示:
除了上面提到的IP地址外,还有一些特殊的IP地址,比如0.0.0.0对应当前主机。255.255.255.255是当前子网的广播地址。127.0.0.1到127.255.255.255.255这些地址都是用来做回路测试的,例如127.0.0.1也可以代表本机IP。
其实,对于主机号,在应用的时候也可以将其拆为子网号和主机号,因此通过IP地址加上一个子网掩码,即可将IP地址分为网络号,子网号和主机号。
二.关于ICMP协议
通过前面的介绍,我们知道IP协议是通过路由的方式一跳一跳的将数据发送到目的端,但是并不是所有发送过程都是没问题的,实际上会发生异常的概率还不小。此时发生问题的路由器或主机将通过ICMP协议来将重要信息返回给源主机。
ICMP协议被认为是IP层的组成部分之一,我们依然将其理解为是网络层的协议。ICMP协议是基于IP协议的,ICMP协议的全名为Internet Control Message Protocol,即Internet控制报文协议。其在IP主机,路由器等设备之前传递控制消息,主要包括网络是否连通,主机是否可到达,路由是否可用等信息。
1.ICMP的报文格式
ICMP的报文格式如下图所示:
可以看到,ICMP报文的前4个字节是固定的。
第0到第15位:标识ICMP类型和对应的code码。其中前8位标识类型,后8位标识code码。
第16到31位:包含了正哥ICMP数据报的校验和,与IP头部的校验和作用一样。
其他位的数据格式并不统一,会根据ICPM报文类型的不同而有所差异,总之,type和code最终会确定ICMP报文的完整格式。
2.ICMP协议的类型
下图完整的列举了ICMP报文所定义的类型:
可以看到,ICMP报文会在IP服务产生错误的时候将异常信息回执给源主机,但是,为了避免网络风暴的产生,并非所有异常都会产生ICMP回执,下面几种场景不会发送ICMP数据报:
1.ICMP本身的IP层错误。
2.目的地址是广播或多播地址的IP报。
3.作为链路层广播的数据报。
4.不是IP分片的第一片的数据报。
5.源地址是零地址,回环地址,广播地址或多播地址的数据报。
3.ICMP的应用
ICMP是IP层必不可少的功能协议,其除了用来协助IP层处理相关逻辑外,在网络嗅探方面也有很大的应用。
1.Ping工具
在前面的ICMP类型表中,有一项type为8,code为0的ICMP类型,其表示进行回显请求,即我们使用此格式的ICMP报文发送给目的主机后,要求主机将发送的数据再回发给我们。这一功能非常有用,我们可以使用它来测试目的主机是否是可达的。平时常用的Ping工具就是基于这种原理实现的。
我们可以先来体验下,可以在终端输入如下指令,发起ping请求:
ping huishao.cc
上面指令的功能是对域名huishao.cc进行ping测试,一次完整的ping测试会产生两个ICMP数据包,一个是请求的,一个是回显的,如下图所示:
通过请求和回执的时间戳,我们可以计算出网络传输中的耗时情况,从而分析网络稳定性。
2.traceroute工具
前面我们提到过,IP层中的任何一个中间设备,也包括起始设备,都不知晓完整的路由链路,有时候为了分析问题,我们需要获取网络通信中一个IP数据包在传输过程中每一跳的处理情况,这时也可以通过ICMP协议完成。你应该还记得,IP协议头中有一个标记生命时间的字段,每个中间路由器处理IP数据报后,都会将这个字段的值减1,当其为0时,路由器则不再转发,直接返回一个type为11,code为0的ICMP数据报。我们可以通过运用这一特新,依次向目标主机发送TTL递增的IP报文,从而探测从源主机到目的主机间所有路由过程。
例如在终端输入如下指令:
traceroute huishao.cc
通过Wireshark工具的抓包,可以看到TTL递增的IP报文与对应的ICMP回执,如下所示:
可以看到,traceroute程序发起的探测包里实际是UDP格式的数据,对应的ICMP数据包中会将当前对应的IP数据头和UDP数据。
三.结尾
本系列博客,核心的目的是能够直观的自上而下的理解网络。以平时最常用的网站访问开始,我们了解了域名解析的DNS协议,处理应用数据的HTTP以及更加安全的HTTPS协议,负责数据可靠性传输的TCP协议,以及本篇所涉及的网络层负责选路的IP协议。当然,文章所介绍的内容都只是起到抛砖引玉之效,其中每个细节点涉及的技术都可以扩展开来学习。目前对我们来说,整个互联网的架构正在逐步的变得清晰,但是还不完整,归根结底,网络的通信是要在实实在在的物理机上面进行,IP地址只是抽象的网络地址,那么网络设备是如何根据IP地址找到对应的物理机的?更多网络层的协议以及网络层之下又是怎样工作的,我们后面再聊!