TCP/IP 系列之重新认识 IP 地址

TCP/IP 系列第三篇,关于 IP 地址。这是我最有意愿分享,也最有趣的一个话题。IP 地址有意思的地方在于,虽然只是一个简单的 IP 地址,短短的 4 个字节,32 bits,里面包含的知识却是森罗万象。智者看山,目之所及,胸中自起万千丘壑。知识底蕴够丰富,才能窥见一个 IP 地址里所隐含的「花中世界」。

预热

在开始之前,需要做一些基础知识的预热。要对基本的位运算有所了解。很简单,明白 & 和 运算即可。

任意 bit 位 & 1 = 任意 bit 位

任意 bit 位 & 0 = 0

另外需要对 2 的常见指数值倒背如流:2º=1,2¹=2,2²=4,2³=8 ,一直到 2 的 10 次方为 1024。

为什么要有 IP 地址

首先,我们要搞明白什么是互联网,也就是我们平时所说的 internet。互联网解决的是设备之间的连接问题,目标是让设备 A 的信息能准确的送达设备 B。为了实现这个目标,我们需要先了解互联网的结构。internet 其实是由无数个子网所构成,是一个二级的结构,第一级是子网,第二级才是子网中的设备。所以 internet 中设备 A 的信息要抵达设备 B,必须先要找到 B 所在的子网,进而再在子网中找到 B。这就是一个路由的过程,我们打个比方,换个角度来描述。

就拿最近火热的一部电视剧「大秦帝国之崛起」来说。战国时期,各诸侯国其实就构成了一个典型的 internet 结构,各国独立是一个子网,各大大小小的子网组合起来,就构成了 internet。秦国大王想送一封信到赵国,这就涉及一个完整的信息路由过程,分为以下几步:

  • 首先秦国信使要离开王宫,带着信件踏出秦国。
  • 其次,信使要先找到赵国位置,中间会路过其他各国。
  • 最后抵达赵国,入赵国之后才能被进一步引见至赵王,递交信件。

上面三步,涉及两个过程。第一是寻找子网的过程,第二是在子网内寻找个体的过程。要做到这两点,IP 地址的设计就要能反映这两个过程。我们来看 IP 地址的机构。

IP 地址 = 网络地址 + 主机地址

IP Address = Network ID + Host ID

IP 地址就是这样一个二级的结构,因为只有二级的结构,才能实现我们上面所说,二级的路由寻址过程。那么对于一个 32 位的 IPv4 地址,我们如何确定哪部分是 Network ID,哪一部分又是 Host ID 呢?我们有请子网掩码(subnet mask)。

子网掩码是很多同学耳熟却不能详的一个概念,简单来说,subnet mask 就是为了分割 Network ID 和 Host ID 的。subnet mask 也有一段有趣的进化历史,值得一提,如何切割 IP 地址经历了一个从「偷懒」到「机智」的过程。

我们先看一个典型的 IP 地址,10 进制和 2 进制:

123.125.114.144

01111011.01111101.01110010.10010000

网络协议的设计者肯定都是聪明人,但最开始,这帮聪明人在设计 IP 地址的切割机制时,偷懒了。有人一拍脑袋,IP 地址不是 4 个字节吗,那简单点吧,我们就按字节切割,那么有以下几种方式:

  1. 第一个字节为 Network ID,剩下三个字节为 Host ID
  2. 第二个字节为 Network ID,剩下两个字节为 Host ID
  3. 第三个字节为 Network ID,剩下一个字节为 Host ID

上面这三种切割方式所划分出来的 IP 地址,就是我们经常所说的 A 类地址,B 类地址,C 类地址。实际上,还有 D 类和 E 类,只不过是做保留实验之用,一般很少提及。

那么我们如何确定一个 IP 地址是属于 A B C 的哪一类呢?我们以第一个字节来做一些约定:

  • 如果第一个字节的起始比特位为 0,则是 A 类地址。
  • 如果第一个字节的起始比特位为 10,则是 B 类地址。
  • 如果第一个字节的起始比特位为 110,则是 C 类地址。

每一类地址里,Network ID 剩下的比特位则用作实际的 Network ID。依次,我们不难进一步得出结论,我们根据第一个字节的数字就可以判断地址类型:

A 类地址的范围为:1 - 126

B 类地址的范围为:128 - 191

C 类地址的范围为:192 - 223

好了,我们终于说完了第一种 IP 地址的切割方式,明白了所谓的 A B C 类 IP 地址。但这种方式很偷懒不是吗?它的问题很明显,IP 地址的切割方式太粗糙,粒度太大。比如说 B 类网络地址,Host ID 只占两个字节,一个子网里也有 65536 个 Host ID,现实世界中哪有那么大的机构和组织,可以使用完 6 万多个 IP 地址呢?即使是alibaba 这样的大公司,也无非是 2-3 万人,所以,这里面存在极大的地址浪费,这种机制太偷懒了!

于是有了第二种 IP 地址切割方式,有另外聪明人看不下去了,提出了 CIDR,来解决第一种切割方式挖的坑。接下来,我们好好说下 CIDR 的概念,这也是如今 internet 路由所使用的切割方式。好啦,先总结一下,所谓的路由寻址,第一步是找到正确的 Network ID 地址,其次再是找到正确的 Host ID。

插播另一个知识点,解释下路由器(router)和网关(gateway)的差别,在后面路由表的学习中还会用到。其实 gateway 是一种特殊的 router,gateway 用于连接两种不同的网络,比如从子网进入 internet 的路由器就是 gateway,信使离开秦国,秦国的国门就是 gateway,连接的是秦国和茫茫九州。gateway 中的 gate 意为门,很形象不是吗?一个 IP 包离开 gateway 进入 internet 之后,还要在若干个普通 router 之间进行路由,这些路由就不能称之为 gateway 了。

CIDR

终于到了今天的主角 CIDR,全称为 Classless Inter-Domain Routing,名字有些绕口,这不重要,第一个单词 classless 就表明了,CIDR 是与上面提到的,以分类(class)来切割 IP 地址的方式所对应的新方式。CIDR 是新的子网掩码的表达方式和路由方式。这里注意 CIDR 和 CIDR notation 的区别,CIDR notation 是描述 IP 地址如何切割的方式,而 CIDR 描述的是基于 CIDR notation 的路由方式。

CIDR notation 其实概念也很直白,它不再粗暴的以字节为粒度来切分 IP 地址,而是精确到 bit 位,我们看一个典型的 CIDR notation:

123.121.114.144/23

注意 IP 地址后面的 /23,这就是 CIDR notation,它表示 IP 地址的前 23 bits 为 Network ID,剩余的 9 bits 为 Host ID。23 并不是 8 的倍数,我们将切分的精读提高到了 bit。我们可以通过简单的位运算,得到具体的 Network ID 和 Host ID,我们将 IP 地址和 /23 先转为二进制:

01111011.01111001.01110010.10010000 IP 地址

11111111.11111111.11111110.00000000 /23 subnet mask

上面两个二进制进行与操作,我们就可以得到 Network ID 和 Host ID:

01111011.01111001.01110010.00000000 Network ID

00000000.00000000.00000000.10010000 Host ID

再将二进制转换为十进制,我们就得到了便于理解的 Network ID:123.121.114.0。由于 Host ID 占用 9 个 bits,这个子网里一共可以有 2 的 9 次方个主机数,也就是 512 个主机,这个子网网段的起始地址为 123.121.114.0,结束地址为 123.121.115.255。我们对于某一个网段内的 IP 地址,有个约定,第一个地址为 Network ID,最后一个地址是该子网内的 Broadcast ID,那么剩下的可用于子网内设备的 IP 地址数量就是 510 个了。

出一个小题目,一个 IP 地址,可用于 Network ID 的部分最多是 30 位,这是为什么?

希望阅读到这里,大家能大致明白 CIDR notation 的含义了。CIDR notation 只是为了以更小的粒度来切分 Network ID 和 Host ID,为了方便路由器能正确的识别出 IP 地址的结构,从而进行路由。

记下来我们要进入下一个话题,IP 包是如何进行路由的?

路由

关于路由的讲解,我们分为两部分。首先我们需要明白 IP 地址是如何分配的,其次是 IP 包是如何基于路由表进行路由的。

IP 地址分配

IP 地址虽然只是一个二级的结构,但 IP 地址的分配却是一层一层,经历多层往下分发的,由一个国际机构 IANA 统一分配。具体规则可以参考 IANA 官网:https://www.iana.org/numbers

IANA 会先按区域,将一大块 Network ID 分配个下一级的机构,下一级结构按大小可以分为:Local Internet registry (LIR),National Internet Registry (NIR),Regional Internet Registry (RIR),比如亚洲的 APNIC 就是一种 Registry。

Registry 拿到的是一个比较大的 Network ID 范围,比如:

Registry A 拿到的是 123.121.114.144/10

Registry B 再从 Registry A 那拿到 123.121.114.144/15

。。。

然后 ISP (运营商)从 Registry X 那拿到一个更小范围的 Network ID,最后 ISP 才会将这一范围内所包含的 IP 地址分配给用户。

所以整个流程是以 Network ID 块的大小为层级,一层层分发下去,越往下,Network ID 块所含的 Network ID 数量越少,所拥有的 IP 地址自然也越少。

路由表

用户拿到 IP 地址后,所发送包要经过一个个的路由器才能抵达正确的地址。理解路由器的工作原理之前,先要明白路由表的概念。

网络上的路由设备,包括发送方本机,都是通过路由表来决定包将发往何方的。在 Mac 上,可以通过如下命令来查看本机的路由表:

netstat -r

每一个包都有它的目标 IP 地址,路由表就是根据目标 IP 地址,决定将包发往哪个设备。我以本机的路由表输出为例简单讲解下,大家也可以自己去多查阅下相关的资料。

表的第一列为 Destination,用来规定目标 IP 地址的范围。Destination 可以是某一个具体的 IP 地址,用作精确匹配,也可以是使用 CIDR notation 来表达某个 IP 地址的范围。比如 192.168.3.3/24 表示,所有 Network ID 为 192.168.3.0 的 IP 地址。表的每一行为一个匹配记录,路由表会拿目标 IP 地址一行行的去匹配,直到找到最精确的匹配记录,如果找不到,则使用第一行 default 记录,default 记录对应的 gateway 即为局域网的默认路由器。

第二列为 Gateway,是 IP 包的下一个抵达位置,如果我们将 IP 包从局域网发送到公网的某一个地址,那么 Gateway 的值就是我们局域网的默认为网关,也就是上面提到的 default 记录。

第三列是 Flags,这个大家可以自己查阅资料来理解。最常用的比如 U 表示 UP,意味设备正常运行,G 表示 Gateway,即我们的路由器。

倒数第二列为 NetIf,即 Network Interface,也就是我们的网卡,一般设备都有多个网卡,比如无线网卡,以太网卡,路由表里的记录还定义了 IP 包将经由本机的那块网卡发送。

最后一列是路由表记录的过期时间。

理解路由表的关键在于明白 IP 地址的结构,和 CIDR 的表达方式,这样我们才能明白路由表里记录的匹配方式,才知道一个 IP 包在本机是如何决定下一个目标设备的。

路由器的工作方式也是由类似的路由表来决定的,那么路由表里的记录是怎么来的呢?有些是手动配置的,叫做 static routing,剩下的是通过算法生成的,叫做 dynamic routing,这个话题就涉及到路由的工作方式了。

路由的工作方式

路由的工作原理包含的知识点较多,以后会单独开篇讲。这里只向大家推荐一个我收藏的 youtube 教学视频,讲解不同网络之间包是具体如何路由的,非常清晰。附上地址:https://www.youtube.com/watch?v=C5YfkR8LGm0&list=PLOa9HH-ix1x3JqNc4nNGD9JklAnQq6eMW&index=2 。

总结

关于 IP 地址,还有很多有趣的知识点可以谈论,后面应该会有更多的相关分享。这篇读完,希望初学网络协议的同学们,下次再看 IP 地址,能有「看山不是山」的境界,全文完。

欢迎关注公众号:MrPeakTech