IPv4 地址耗尽,为什么 IPv6 没有广泛将其取代?
共 8341字,需浏览 17分钟
·
2024-05-24 08:00
【CSDN 编者按】IPv6 作为全球公认的下一代互联网商业应用解决方案,为解决 IPv4 地址枯竭而制定的下一代互联网协议版本。今年年初,因 IPv4 将耗尽,巨头企业宣布收费后,开发者对 IPv6 的发展尤为关注。本文作者 Sedat Kapanoglu 也不例外,尽管他知道 IPv6 有二十多年,但一直以来对它的理解仅停留在“为了解决 IPv4 地址空间不足而设计的一个过度工程化的解决方案”。
近日,他深入学习了 IPv6 的工作原理,发现其中有不少有趣的知识想和大家分享,同时他表示自己并非 IPv6、网络工程的专家,假如你也对 IPv6 感兴趣,一起看看作者说的对不对?
原文链接:https://ssg.dev/ipv6-for-the-remotely-interested-af214dd06aa7
IPv6 vs. IPv4
我一直对IPv6这个名字感到困惑,因为我觉得IPv4名字来源于它用来表示32位的四个字节,所以IPv6应该被称为IP16。但实际上,这只是协议的版本号。
在IPv4推出之前,曾存在过IPv1、IPv2和IPv3,它们主要用于内部研究IP协议,后来被我们现在的IPv4所取代。在上世纪80年代,还提出过IPv5的提案,旨在优化实时通信,但大家发现IPv6能解决地址空间问题后,该提案就被放弃了,因此才有了IPv6这个名字,代表互联网协议第6版。后来有人尝试创建IPv7、IPv8等更高版本,但它们要么已被废弃,要么被搁置起来。
和IPv4一样,IPv6有自身的寻址方案,但它使用的是128位地址而非IPv4的32位地址。这两种协议之间的差异不仅体现在地址空间大小上,而且与IPv4对比,IPv6有其独特特性,比如:
IPv6没有子网掩码
IPv6和IPv4同样支持CIDR(无类别域间路由),但从用户角度看,IPv6地址要简单得多:前半部分是全球互联网地址,后半部分是本地地址。这是推荐的IPv6地址使用方式。当你访问某个显示IP地址的网站如WhatismyipWhatever时,它会显示出你的IPv6地址形式如下:
1111:2222:3333:4444:5555:6666:7777:8888
但是,你的互联网服务提供商(ISP)只知道你的前缀部分为1111:2222:3333:4444,并将这个/64的地址块分配给你。地址的剩余部分对你的网络中的每一台设备都是独一无二的。ISP只会将所有以1111:2222:3333:4444开头的数据包转发至你的路由器,然后路由器会将数据包进一步传递到目标设备。因此,地址的后半部分(5555:6666:7777:8888),我们可以称之为INTERFACE_ID,这部分对于你的设备来说是唯一的。这就意味着你拥有的每一台设备都拥有一个独特的IPv6地址,可以从世界任何地方单独访问,原因在于:
IPv6 不使用 NAT 技术
实际上,针对 IPv6 的 NAT(Network Address Translation,是指网络地址转换) 并不存在公开的标准规范。虽然有一个名为 NAT66 的草案提议,但至今并未转化为现实标准。
之所以在 IPv6 中不需要 NAT,是因为理论上地球的每个设备都可以有一个独立的全球可访问的地址。开始我对此感到很奇怪,因为在玩网络游戏时虽然我们常常痛恨 NAT 导致的种种不便,但它却给人一种安全感,除非你明确通过 UPnP 或端口转发允许,否则你的本地设备永远不会被外部网络直接访问。
有一个残酷的事实是,NAT 并不是一道安全屏障,它只是一个替代的数据包转发机制。在默认情况下,你的IPv6路由器本不应随意将来自外部的连接尝试转发给本地设备。因此,在 IPv6 环境下,即便不使用 NAT,你也同样可以获得相同级别的安全保障。实际上,借助IPv6地址,你无需经过路由器,或者不必另行配置VPN,就能直接访问本地网络上的每一台设备:只需要进行身份验证即可。
尽管IPv6为每台设备分配独立的IPv6地址带来了便利,但也存在一个与安全相关的问题:由于每个设备都有独一无二的地址,因此它们可以被个别识别和跟踪,这对我们的隐私保护构成威胁。为此,现代操作系统引入了临时IPv6地址的概念,该地址的INTERFACE_ID会定期变化。这样一来,你可以使用永久IPv6地址接收外部的连接请求,而在建立连接时,对外展示的是一个频繁变动的二级临时地址作为你的IPv6地址。
接下来我们继续探讨IPv6的特性:
IPv6地址具备自动配置功能
IPv6协议无需依赖DHCP(Dynamic Host Configuration Protocol,动态主机设置协议)服务器或手动网络配置来确定IP地址、子网掩码及网关地址。一台设备可以不通过询问中央服务器而自主获取IP地址。这一过程是通过一个名为SLAAC(Stateless Address Autoconfiguration,无状态地址自动配置)的协议实现的,具体步骤如下:
操作系统(特别是操作系统的IPv6堆栈)会生成一个64位的设备标识符,通常是随机生成的,比如5555:6666:7777:8888,这个标识符构成了你的IPv6地址INTERFACE_ID部分。
操作系统会在该INTERFACE_ID前加上fe80,这是仅限本地使用的IPv6网络前缀。因此,你现在得到的IPv6地址是:fe80::5555:6666:7777:8888。(请注意这里的"a::b"语法表示的是:“在'a'和'b'之间存在所有值为零的段”。关于这点我们稍后再详细介绍。)
你的设备会将一个数据包发送到本地网络上指定的邻居多播组,以确保没有其他设备使用相同的IPv6地址,这被称为重复地址检测(DAD)。而分配到重复地址的几率很小。
设备将它获取到的本地地址发送给路由器(与IPv4不同,在IPv6中,路由器始终可以通过组播地址ff02::2被访问到),并通过发送一个RS(路由请求)ICMPv6数据包来请求路由器的实际前缀。路由器收到请求后,会通过RA(路由通告)数据包回应,并用回复的实际前缀替换掉fe80,设备随后开始使用这个新的地址作为其永久地址。这就是你现在的IPv6互联网地址。
如此一来,无状态配置的优势在于减少了路由器上的管理开销:路由器无需单独维护网络中每个设备的IP配置信息。意味着这将可以带来更好的性能表现,特别是在大型网络中尤为明显。
IPv6的“神话”
IPv6也有一些夸大的说法,我们一起梳理澄清下:
你设备只有一个IPv6地址,可用于在所有地方
确实,你会使用同一个IPv6地址进行本地和远程连接。但是,“一统天下之IP地址,寻遍万物之IP地址”的说法并不准确。正如我之前所提到的,你的设备会为了不同范围的目的声明多个IPv6地址,比如链路本地(fe80::)和互联网。此外,你的设备也可能获得两个不同的公网IPv6地址:永久地址和临时地址。临时IPv6地址旨在保护你的隐私,它们会定期轮换。而永久IPv6地址主要用于必须具有静态IPv6地址的服务器。
为宇宙中每个原子分配一个IP地址
还远远不够的。宇宙中大约有2²⁷²个原子,地球约有2¹⁶⁶个原子,所以我们至少需要168位(八位对齐)的地址空间来容纳它们。实际上,IPv6的地址空间略小于128位:前16位是IANA预留的。因此,你只能用剩下的112位来标识设备。尽管这非常多,远超过我们在未来几千年里地球上可能制造的所有设备的数量,但并不能为每一个原子分配一个独立的IP地址。然而,我们可以为地球上的每一粒沙子分配IPv6地址,甚至我们还可以将这些地址全部装进一个单一的/64前缀内。总之,IPv6地址空间是极其庞大的。
每个设备的通用连接
没错,IPv6没有NAT机制,这意味着不再需要端口转发或维护地址空间。但是,如果你想建立直接连接,仍然需要有一种机制允许远程主机连接到你的设备。默认情况下,你的路由器/防火墙会阻止任何连接尝试。你会怎么做呢?
就像UPnP/IGD时代一样,今天的应用程序仍然需要与PCP(端口控制协议)这类协议配合工作,才能以编程方式打开端口访问权限。所以,并不是说你突然间就能凭借全局+本地IPv6地址实现通用连接。虽然你不必手动设置端口转发,但应用程序仍需与路由器协作才能使自身变得可访问。
从我看来,在某些情况下,IPv6的表现甚至不如IPv4:
IPv6的不足之处
在IPv4环境下,我们习以为常的一些功能,当过渡到IPv6后可能会让你怀念,例如:
依赖ISP提供子网划分服务
由于IPv6不采用NAT技术,许多美国ISP默认只向你的路由器转发一个64位前缀(通常称为“/64”)。这意味着路由器无法在IPv6地址中嵌入子网信息。要知道,IPv6地址是由设备自动配置的,因此路由器无法强制这些设备使用小于64位的本地地址,这让路由器无法知道应该将数据包转发到哪个子网。
你得依赖于ISP提供短于64位的前缀,这样你的路由器才能利用剩余的比特位来识别数据包应当发往哪个子网。理论上讲,通过分配60位前缀,ISP实际上完全有能力给家庭用户提供至少16个子网,但不知道为何他们并没有这样做。或许是因为他们在IPv4地址空间匮乏时期的心理创伤让他们变得贪婪?或者是他们想通过额外收费来赚钱:“嘿,如果你想要更短的前缀,那就多付点钱给我们。”据我所知,Comcast Xfinity和AT&T两家公司都只为家庭用户提供了一个简单的/64前缀:即单个子网。
你或许会说,家庭用户可能根本不需要子网划分,但是随着物联网设备的普及以及我们对网络安全越来越高的依赖性,隔离不可信设备的重要性正在日益凸显。欧洲IP地址分配权威机构RIPE建议住宅ISP客户使用56位前缀,这样每位客户可以获得256个子网,这是欧洲提出最贪婪、也最保守的选项,而在美国,这几乎是可望而不可及的梦想。
当然,你可以手动配置每一台设备的IPv6地址,并以此方式赋予它们子网标识符,但这将是一项巨大的工程,尤其是考虑到添加新设备时带来的管理负担。难道你想退休后变成一个人工DHCP服务器吗?
IPv6地址在URI中需要额外编码
我们可能都试过在浏览器输入“http://192.168.0.1”并访问路由器设置。在URI规范中“:”字符是为端口号保留的,所以如果没有额外的编码,无法直接采用相同的方式来访问IPv6地址。若想通过IPv6地址访问一台设备托管的网页,必须采用如下格式:“http://[aaaa:bbbb:cccc:dddd:eeee:ffff:1111:2222]/path/?query”,注意地址两边的方括号。但这还不是最糟糕的部分,因为:
IPv6地址难以记忆
理论上我们不应去记住IP地址,但实际情况并非如此。对于IPv6地址,我至今也无法确定可靠且一致地访问自家路由器所使用的地址。确切地说,我无法记下它的完整IP地址。mDNS有助于解决这个问题,但它也不总是稳定有效。
十六进制数字相比十进制数字也更为复杂。这就像是试图记忆Windows XP产品激活码一样困难。
记住IPv4地址是一种通用技能,由于普遍存在的NAT技术,多数情况下“192.168.1.1”都能派上用场,我们无需查询。而在任意设备上找出路由器的IPv6地址则需要不同的技巧。
从积极的一面看,现在你知道IPv6地址的最右侧64位部分始终是随机生成的,所以至少可以避免误以为它是固定不变的或者是有意义的。你可以将这一部分称作BLABLA而非INTERFACE_ID。你可以记住你的/64前缀,至少能找到路由器的地址,通常是类似1111:2222:3333:4444::1这样的形式。
IPv6地址复杂
当然,IPv4地址同样复杂。你知道2130706433是一个有效的IPv4地址吗?或者换种写法,0x7F000001、0177.0000.0000.0001,以及127.1其实都是一回事?如果不信,你大可在终端尝试ping它们。虽然很难相信,但它们全等同于127.0.0.1这个地址。
IPv6地址在表示形式上也有类似的多样性。以下是其一些特征:
IPv6地址的表示方法相对复杂,由8个十六进制分组组成,这些组被称为“hextet”(实际上“Hextet”是hexadectet的误称,但现在已约定俗成)。这样一来,就可能出现类似的十六进制表达技巧:
IPv6地址中的零值前缀不会显示,因此2600:00ab实际上显示为2600:ab。
如前所述,如果某个十六进制四字组的值为零值,可以完全从地址中删除,并用双冒号代替。因此,2600:ab:0:0:1234:5678:90ab:cdef将显示为2600:ab::1234:5678:90ab:cdef。看到双冒号了吗?不过要注意的是,这种简化方式只能应用于地址中首组连续的零值四字组。因此,2600:ab:0:0:1234:0:0:cdef仍显示为2600:ab::1234::0:cdef。另外,不能仅仅简化单个零值的十六进制四字组。因此,2600:0:1234:5678:abcd:ef01:2345:6789中的零值保持原样,不会被省略。
你可以指定区域ID:通过在地址末尾添加“%”后缀和区域ID来指定要通过哪个网络接口访问该地址。例如,当你同时通过WiFi和以太网连接到同一网络时,你可能想要通过局域网来ping你的路由器。在这种情况下,你需要在地址后面追加“%”符号,并添加你的区域ID(即网络适配器标识符),例如fe80::1%eth0或fe80::1%3。问题是,在IPv6 URI中除了需要用到方括号之外,你在浏览器地址栏或其他需要在URI中使用区域ID的地方,还必须将“%”转义为“%25”。
IPv6地址还可以用来表示IPv4地址。因此,你可以通过在其前方添加IPv4转换前缀的方式,使用IPv6地址语法来ping 127.0.0.1,这时它将被视为一个IPv4地址,即:::ffff:127.0.0.1。但这并不意味着你的IPv4请求会通过IPv6网络进行传输,而是告诉底层网络协议栈使用IPv4连接。如果选择不同于::ffff的前缀,IPv4部分将会被合并到最后两个十六进制字节中,并通过IPv6网络与该IP地址建立连接。例如,IPv6地址2600:1000:2000:3000::192.168.1.1会被视为2600:1000:2000:3000::c0a8:101,其中最后两个十六进制字节相当于IPv4地址192.168.1.1的十六进制表示形式。
这些都是有效的IPv6地址:
:: 表示所有零,即0:0:0:0:0:0:0:0.
2600:: 相当于2600:0:0:0:0:0:0:0.
::ffff:1.1.1.1 等同于IPv4地址1.1.1.1 。
2607:f8b0:4005:80f::200e 是我ping google.com时获取的地址,与2607:f8b0:4005:80f:0:0:0:200e等效。可以看出,像Facebook一样,Google也选择了艰难的道路,决定为其IPv6地址手动分配特定的INTERFACE_ID。
最终,在地址栏中输入的IPv6地址可能看起来像下面这个人为构造的例子:
https://[542b:b2ae:ed5c:cb5a:e38b:2c49:123:192.168.1.1%25eth3]
我可记不住这么长的地址。
通过这次学习,让我对IPv6的相关知识有了更清晰的认识。例如,我以前不知道IPv6地址是通过无状态协议自动配置的,也不知道IPv6中没有NAT技术,更不了解地址空间是如何恰好被便捷地划分为两半的。
我希望我们能有一个指向默认网关的快捷IPv6地址,我提议使用fe80::1。国际互联网工程任务组(IETF),不妨考虑一下这个提议哦!
我还记得当初Windows 2000宣布支持IPv6时,那是个重大的进步,我们都认为IPv6将在十年左右的时间里被广泛采用。没想到我们错得离谱!然而,通过对IPv6的学习,我才理解到为什么这项技术没有快速普及起来。
IPv6并未对终端用户提供实质好处
尽管IPv6在技术上较为先进,但IPv4却简单实用,即使是在NAT(网络地址转换)之后,甚至是多层NAT环境下,面对地址空间极度紧张、DHCP配置繁琐、端口转发复杂的条件下,IPv4依然能够正常运作。只要出现问题,总有人找到解决方案使其继续工作。
理论上IPv6因无需NAT可能具有更低延迟的优势,但这点改进还不足以显著提升用户体验,不足以让用户强烈要求切换至IPv6。
正因为IPv6并未带来直观可见的好处,用户并不会主动要求使用,往往是在他们不知情的情况下被推向IPv6,就像我们现在在移动网络中几乎默认使用IPv6一样。
这意味着,一旦互联网服务提供商感受到IPv4的限制带来的足够压力时,它们将会立刻切换到IPv6。
我希望IPv6能够开启一些IPv4无法实现的独特功能场景,让用户能够因为想要使用这些功能而主动需求IPv6。尽管如此,我还是喜欢IPv6特质,期待有一天我们完全放弃IPv4,转而围绕IPv6来构建所有网络服务。
开发者怎么看?
正如作者在开头说自己并非是IPv6、网络工程的专家,读完他的文章后,一些开发者提出自己的观点:
开发者@9dev 表示,对终端用户而言,真正的益处在于整个互联网协议栈回归到它应有的完全透明状态。用户不应该再需要操心IP地址问题;IPv6使得设备真正实现“即插即用”,即设备能够自行获取地址,自行协商连接。理想情况下,用户再也不必关心这部分连接问题。的确,IPv6给网络运营商带来了复杂性,但这也是复杂性应当的。
@lxgr 在学习这篇文章后,针对作者提到的一些看法,有不同的意见:
针对“IPv6没有子网掩码”的说法,他认为绝对是有子网掩码的,只不过在IPv6中它们被称为前缀长度。/64前缀刚好适合与SLAAC(无状态地址自动配置)配合使用。
针对“IPv6没有NAT”的说法,同样,IPv4也没有自带NAT。NAT是一种路由器可以选择实现的技术,当然在IPv6中也同样可行。例如,Linux操作系统就实现了IPv6的NAT,只拥有一个IPv6地址的情况下,例如从本地网络获得一个地址并在机器上运行虚拟机时,IPv6的NAT可能是必不可少的。
针对“IPv6地址是自配置的”的说法,有时确实是这样,但也有时候并非如此,还有DHCPv6和静态配置的方式。
针对“IPv6地址无法记住”的说法,那又怎样呢?反正他也没兴趣记住IPv4地址、电话号码等信息。
针对“IPv6对终端用户没有好处”的说法,作为终端用户,他发现IPv6给我带来了很多好处:
防火墙穿越比NAT穿越更可预测且成功率更高。像VoIP、Tailscale等服务在IPv6环境下相比跨越一层或多层NAT的成功率大大提高。
家里的所有设备都可以获取公网地址,他可以通过路由器上的防火墙规则选择性地开放入站连接。
移动网络上的路由更为直接,从而降低了延迟(IPv4常常需要通过一系列昂贵且具有状态的CG-NAT设备,在使用的移动网络服务商部署IPv6的地区,这种情况得以避免)。