为什么 IPv6 地址中有一个百分号“%”?

Ami*_*rge 149 ipv6

我正在使用这些.NET Framework类来获取我机器的 IP 地址。

Dns.GetHostAddresses(Dns.GetHostName())
Run Code Online (Sandbox Code Playgroud)

我有一个 VirtualBox 适配器,它同时具有 IPv4 和 IPv6 地址。使用 .NET 代码,我将 IPv6 地址作为fe80::71a3:2b00:ddd3:753f%16

注意到末尾的 %16 了吗?

但是,如果我使用相同的查询WMI,我得到的地址为'fe80::71a3:2b00:ddd3:753f'

那么,%16 有什么特殊意义吗?

编辑:

我只是对此有更多的观察。它们与斯蒂芬詹宁斯在他的回答中所说的非常吻合。

我安装了 Vmware 以查看它发出的 IPv6 地址。地址是:fe80::3dd0:7f8e:57b7:34d5%19

fe80::b059:65f4:e877:c40%20

显然,% 之后的数字不是某种十六进制表示。我使用 Wmi 检查了网络适配器的所有可用属性,发现这些数字与每个网络适配器的 InterfaceIndex 属性完全相同。根据MSDN,它唯一标识每个网络适配器,这个属性是在 Vista 中引入的。

仍然让我感到困惑的是,为什么 IPAddress 类允许您以该格式创建 IP 地址,除非它有效。斯蒂芬提供了答案。数字是范围 ID。IPAddress 有一个接受地址和范围 ID 的构造函数。

哦,所有这三个网络适配器都是本地链接。通过 ipconfig 确认

凉爽的。那很有趣!!

Ste*_*ngs 148

'%' 后面的数字是作用域 ID。

IPv6 至少为地址定义了三个可达范围:

  1. 全球可寻址。这是您的 ISP 提供给您的 IPv6 地址。它可以在公共互联网上使用。

  2. 链接本地。这类似于 169.254.XX 范围。它是计算机分配给自己的地址,以便于进行本地通信。这些地址不会在公共 Internet 上路由,因为它们不是全球唯一的。

  3. 节点本地。这是一个标识本地接口的地址,类似于127.0.0.1。基本上,这是地址::1。

Microsoft 发表了这篇描述 IPv6 寻址的文章,这是我发现的最不容易混淆的文章。文章指出您的地址中存在范围 ID 意味着它是一个链接本地地址。您还可以判断它是链接本地的,因为地址以fe80.

关于此主题的清晰、易于理解的信息似乎很少见,因此我将根据我对RFC 4007和其他信息的最佳理解将其余信息放在一起。

一台计算机可以有多个链接本地地址,每个地址都有不同的范围。范围 ID 指示地址所针对的范围。例如,想象一下有两个 NIC 的计算机的场景,每个 NIC 在不同的网络上都有一个本地链路地址。如果您尝试将某些内容发送到以 fe80 开头的另一个地址,计算机如何知道要发送到哪个 NIC?范围 ID 似乎是解决此问题的方法。

  • @Pumbaa80 客户端将消息发送到 `fe80::1%1` 以到达连接到 NIC #1 的路由器,并将消息发送到 `fe80::1%2` 以到达连接到 NIC #2 的路由器。顺便说一句,本地链路地址由主机自动配置,而不是通过 DHCP,因此它可能不会为其两个 NIC 分配相同的 IP。还要记住,链路本地地址是不可路由的,因此通常您不会向路由器发送消息,而是在两台主机之间发送消息。 (2认同)

Pet*_*aut 29

前缀为 fe80::/64 的 IPv6 地址是链路本地地址,通过将该前缀与网络设备的硬件地址(在您的示例中为 71a3:2b00:ddd3:753f)组合来构造。(IPv4 中的模拟是 169.254.0.0/16。)由于机器上所有链路本地地址的前缀都相同,因此路由有时可能需要知道您指的是哪个接口。这就是百分比后面的数字,称为区域索引,指定的内容。具体取决于操作系统: 在 Windows 上,%16接口编号为 16;例如在 Linux 上,您可能会看到类似%eth0.

某些工具或 API 会认为此区域索引不重要或出于其目的而隐含。例如,在 Linux 上,该ifconfig工具不会显示它,因为地址属于哪个接口很明显。但总的来说,应该考虑到这一点。


TOO*_*GAM 26

% 后面的字符(在您的示例中恰好是数字)是“区域 ID”。(“区域 ID”是用于标识有助于识别要使用的网卡的文本。它可能看起来像网卡的名称,或者只是一个数字。)

这些字符用于标识“网络接口”,人们通常将其称为“网卡”。例如,它可以帮助确定数据包是使用有线以太网卡还是无线 Wi-Fi 适配器。

我猜您正在使用 Microsoft Windows。它使用数字作为区域 ID。虽然 Microsoft 的文档指出了不同类型的区域 ID(我将在本答案的后面讨论),但对于链接本地地址(在 fe80::/64 中),“区域 ID”是网卡的“接口索引”。

相比之下,类 Unix 系统可能会在 % 符号后使用字母。例如:fe80::71a3:2b00:ddd3:753f%eth0

在这种情况下,区域 IDeth0与操作系统通常用于标识网卡的名称相匹配。

在 Microsoft Windows 中,您可以使用检查路由表的命令行之一获取(数字)区域 ID 的列表。我更喜欢“ netstat -nr”,因为它也适用于其他操作系统,但 Microsoft Windows 也支持“ route print”。得到报告的结果输出可能会超过一个屏幕,因此请准备好向后滚动,除非您通过管道传输到更多内容。

例如,在我的系统上:

=========================================================================== Interface List 14...5c f9 dd 6d 98 b8 ......Realtek PCIe GBE Family Controller 12...e0 06 e6 7e fc 4e ......Bluetooth Device (Personal Area Network) 1...........................Software Loopback Interface 1 13...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter 15...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter #2 ===========================================================================

在这种情况下,像fe80::71a3:2b00:ddd3:753f%14这样的地址指的是与“区域 ID”相关的网卡14,它恰好是我的 Realtek PCIe GBE 系列控制器。(“GBE”指的是千兆以太网。)

(您还可以看到许多 Microsoft Windows 版本使用的这些“接口索引”值,例如:“ WMIC NICCONFIG GET Caption,InterfaceIndex,IPAddress /FORMAT:LIST”。在 PowerShell 中尝试这样做的人应该记住在每个逗号之前使用反引号。)

现在,这里是棘手的部分:如果您想 ping 远程地址,您可能需要使用远程系统的 IPv6 地址,但需要使用本地系统的“区域 ID”。因此,例如,如果我使用计算机 A 并且我有一个本地 IPv6 地址 fe80::1 附加到接口编号 14,并且我想 ping 计算机 B 并且它有一个本地 IPv6 地址 fe80::2 附加到它的接口编号为 16,那么这就是我将使用的:

ping fe80::2%14

因此,该ping命令会将 ICMPv6 数据包发送到属于远程计算机的远程 IPv6 地址 (fe80::2),并将使用接口区域 ID 14 来执行此操作。区域 ID 14 是来自我正在使用的系统的数字,而不是远程系统。因此远程系统的地址和指定的区域 ID 来自不同的计算机。

现在,让我们看看为什么这可能是必要的。

如果我想 ping Google 的 IPv6 地址(在我写这个答案时是 2607:f8b0:400a:802::200e),那么路由表将检查哪个网卡处理以 2607:f8b0:400a 开头的地址: 802. 路由表将表明我的所有网卡都没有使用以 2607:f8b0:400a:802 开头的地址直接连接到网络,因此我的计算机最终将使用“网关”地址。如果我要连接到属于我工作的组织的另一个网络,我可能有一个特殊的“网关”地址,可以将流量路由到专用网络。在这种情况下,我没有更具体的网关,因此我将使用 IPv6“默认网关”。这就是 IPv6 大部分时间的工作方式,除了链路本地地址。这也是 IPv4 大部分时间的工作方式。

根据RFC 4291 第 2.8 节,每台使用 IPv6 的计算机都应该为每个网络接口分配一个本地链路地址。 RFC 4291 第 2.5.6 节显示了链接本地地址必须以哪些位开头,这会导致链接本地地址以“fe80:0000:0000:0000:”开头(尽管其中许多零被折叠为双冒号)。RFC 4291 第 2.4 节也描述了这些地址以“fe80:”开头的事实。

如果您尝试 ping 远程系统(例如,“2607:f8b0:400a:802”),一般过程通常是找出地址所属的网络或子网,这是通过查看位来完成的在地址的开头。然后,这些位用于确定如何路由流量。

但是,该过程不适用于 IPv6 链路本地地址,因为每个(可操作的、活动的)网络接口都有一个以“fe80:”开头的链路本地地址,子网前缀/大小为“/ 64"。如果您使用的是笔记本电脑,您可能会发现您的以太网卡和 Wi-Fi 适配器都应该具有这样的 IPv6 地址。

现在,当您将 ping 发送到 fe80::2 时,您希望您的计算机将该数据包发送到正确的网卡上。如果您的打印机连接到有线网络,则您不希望使用不会导致流量到达打印机的网络路径/路由将流量从 Wi-Fi 卡发送出去。如果您尝试使用 Wi-Fi 卡与无线设备通信,您不希望流量从以太网卡流出。

解决方案是让您指定希望流量使用的网络设备。所以,这就是区域 ID 的目的。

答案更新:

  • 这个答案的原始版本(碰巧是我提供的答案中评价很高的答案)最初使用术语“接口标识符”而不是“区域 ID”。
    • 我认为术语“接口标识符”只是我个人编造的一个术语,它基于术语“接口索引”,Microsoft Windows 使用它来标识特定的网卡。然而,“接口 ID”一词被证明是一个不太理想的选择,因为 IETF RFC 文档已将该术语用于其他用途:
    • 术语“区域 ID”来自RFC 4007:“IPv6 Scoped Address Architecture”,第 11 节,“文本表示”(特别是第 11.2 小节)使用了术语“zone_id”。虽然我认为像这样的 IETF RFC 是最权威的,但我也遇到了Microsoft Windows Server 2003 文档:对理解 IPv6 的更新,PDF 第 11 页(印刷第 7 页),它称之为“区域标识符 (ID),也称为范围 ID”。它给出了一个示例,其中 fe80::/64 范围中的“区域 ID”“是连接到包含目标地址的链接的接口的接口索引”,但与 fec0::/48 范围不同的示例是“区域 ID”“是包含目标地址的组织站点的站点 ID。”

    当我偶然发现 IETF RFC 使用的不同术语时,我决定立即更新这个流行的答案,以使其更符合这样一套更官方的标准。(尽管初始版本在书面上很有帮助,但我不希望我的文档与有关 IPv6 地址的官方预先存在的 IETF RFC 标准记录同一短语的方式不同。所以这是 2020 年 1 月 19 日更新的主要原因.)

  • 除了将“接口标识符”更新为“区域 ID”外,2020 年 1 月 19 日更新中还发生了其他细微变化:
    • 添加了 WMIC 命令以获取索引标识符(在 Microsoft Windows 中)
    • 地址中的拼写错误(表示 fd80 而不是 fe80)已修复
    • 小调整,旨在使一些文字更容易澄清
    • 添加了相关技术文档的超链接。(实际上,此类超链接主要包含在本节中,该节描述了此答案的各个部分是如何更新的。)

  • 好的,在重新阅读 [Peter Eisentraut 的回答](http://superuser.com/a/99762/401839) 后,看起来他的技术在技术上是正确的。希望我的细节能提供更多的清晰度。我不同意 [Stephen Jennings 的回答](http://superuser.com/a/99753/401839),因为这个回答看起来像是“范围 ID”将“链接本地”标识为范围。但是,两个不同的网络接口都可以是“本地链接”,但它们不会使用相同的“范围”(根据他的编号列表中显示的示例)。相反,我说这些数字标识了网络“接口”。 (2认同)