0

阅读关于如何以最佳方式表示 IPv6 地址的 RFC 建议 ( RFC 5952 ),我尝试在 C++ 中实现一个函数,该函数将字节数组转换为适当的文本表示,即std::string.

为了检查我的代码是否正确,我将我的结果与inet_ntop( #include <arpa/inet.h>) 返回的结果进行比较。请注意,我实际上使用的是 Windows 等效的#include <ws2tcpip.h>.

在大多数情况下,我的函数具有相同的行为,并且我完全理解基本规则(省略前导零,通过用“::”替换它来压缩最长的零块,等等)。

但有趣的部分如下:据我了解,对于一些特殊地址(IPv4 映射、IPv4 兼容和 IPv4 转换的 IPv6 地址,请参阅RFC 2765),建议以其他十六进制表示法表示IPv4 地址常用的点分十进制表示法的最后 4 个字节。

例如::ffff:0:168.0.0.1::ffff:168.0.0.1::168.0.0.1在其推荐的文本表示中都是有效的 IPv6 地址,并且inet_ntop也得出了该结论。

现在我的问题0:0:0:0:0:ffff:0.0.1.1是:根据 ,IPv6 地址inet_ntop缩短为::ffff:0:101,再次选择十六进制表示。这种行为的原因是什么?我认为因为我们在这里有一个特殊的地址前缀,所以无论最后 4 字节块的前两个字节是否为零,都将使用点分十进制表示法,因此将其写为::ffff:0.0.1.1. 我是误解了 RFC 建议还是inet_ntop在这方面不一致?我观察到这inet_ntop在我的所有其他测试用例中都非常符合 RFC。

我希望你能帮助我。

编辑:经过更多测试后,似乎inet_ntop确实总是选择十六进制表示法而不是点分十进制表示法,即使 IPv6 地址实际上只是那些特殊的嵌入式 IPv4 地址中的一些,如果最后 4 的前两个字节字节块为零。

4

1 回答 1

1

FWIW,在我的 Ubuntu(glibc 2.31)上,我得到:

::ffff:0:168.0.0.1      -> ::ffff:0:a800:1      *
::ffff:168.0.0.1        -> ::ffff:168.0.0.1
::168.0.0.1             -> ::168.0.0.1
0:0:0:0:0:ffff:0.0.1.1  -> ::ffff:0.0.1.1       *

其中两个标记的似乎与您的结果不同,表明此实现无法识别::ffff:0前缀,但并不太喜欢嵌入式0.0.1.1

但是,使用全零前缀,我得到了类似的结果:如果 IPv4 地址的前两个字节为零,则输出格式会更改:

::1.2.3.4           -> ::1.2.3.4
::0.2.3.4           -> ::0.2.3.4
::0.0.3.4           -> ::304
::0.0.0.4           -> ::4

这可能是因为::1不应该变成::0.0.0.1,但这意味着必须为 IPv4 地址以混合表示法显示的内容绘制一些线,至少使用全零前缀。

那么,这可能只是您拥有的库的错误或怪癖吗?如果它确实显示出与全零前缀和其他前缀相似的行为,那么他们可能只是决定采用简单的方法并平等地对待所有前缀。据我所知,无论如何,整个0/8块仍然是为“本地标识”保留的0.0.x.x,所以我想知道像 IPv6 这样的地址是否会嵌入到 IPv6 中。(不过我不知道。)

RFC 还仅将混合表示法指定为“推荐”,因此我们不能说您的实现是错误的。

于 2021-03-04T17:49:59.400 回答