首页 > 解决方案 > Inet6Address 对无效的 IPv6 地址有效

问题描述

java.net.Inet6Address用来验证输入字符串是否是有效的IPv6 地址

这是我的代码片段:

public static boolean isValidIPv6ddress(String address) {
    if (address.isEmpty()) {
        return false;
    }
    try {
        Object res = InetAddress.getByName(address);
        return res instanceof Inet6Address;
    } catch (final UnknownHostException ex) {
        return false;
    }
}

true不幸的是,即使对于以下无效的输入,上述方法也会返回:

System.out.println(isValidIPv6ddress("2A00:17C8:50C:0000:0000:0000:0000:00001"));
System.out.println(isValidIPv6ddress("2A00:17C8:50C:0000:0000:00000000000000:0000:00001"));
System.out.println(isValidIPv6ddress("2A00:17C8:50C:00001235:0000:00000000000000:0000:00001"));

API 是否忽略前导零?还是API中有错误?

标签: javaipv6

解决方案


根据有关 IPv6 地址的有效文本表示的最新 RFC,您遇到了一个错误,或者对 IPv6 地址文本表示的错误解释。IPv6 地址架构的最新 RFC 是RFC 4291,IP 版本 6 寻址架构。该 RFC 有第 2.2 节。表示地址的文本表示(请注意,限制为四个十六进制数字):

2.2. 地址的文本表示

将 IPv6 地址表示为文本字符串的传统形式有以下三种:

  1. 首选形式是 x:x:x:x:x:x:x:x,其中“x”是地址的八个 16 位片段的一到四个十六进制数字。例子:

    ABCD:EF01:2345:6789:ABCD:EF01:2345:6789

    2001:DB8:0:0:8:800:200C:417A

    请注意,不必在单个字段中写入前导零,但每个字段中必须至少有一个数字(2.中描述的情况除外)。

  2. 由于分配某些类型的 IPv6 地址的某些方法,地址通常包含长的零位字符串。为了使写入包含零位的地址更容易,可以使用一种特殊的语法来压缩零。“::”的使用表示一组或多组 16 位零。“::”在一个地址中只能出现一次。"::" 也可用于压缩地址中的前导零或尾随零。

    例如以下地址

    2001:DB8:0:0:8:800:200C:417A 单播地址 FF01:0:0:0:0:0:0:101 多播地址 0:0:0:0:0:0:0: 1 环回地址 0:0:0:0:0:0:0:0 未指定地址

    可以表示为

    2001:DB8::8:800:200C:417A 单播地址 FF01::101 多播地址 ::1 环回地址 :: 未指定地址

  3. 在处理 IPv4 和 IPv6 节点的混合环境时,有时更方便的另一种形式是 x:x:x:x:x:x:dddd,其中 'x' 是六个高位 16- 的十六进制值地址的位片段,'d' 是地址的四个低位 8 位片段的十进制值(标准 IPv4 表示)。例子:

    0:0:0:0:0:0:13.1.68.3 0:0:0:0:0:FFFF:129.144.52.38

    或压缩形式:

    ::13.1.68.3 ::FFFF:129.144.52.38

由于 RFC 4291 要求每个 16 位字段不超过四个十六进制字符,因此认为在 16 位字段中具有四个以上十六进制字符的任何 IPv6 地址文本表示是有效的是不正确的。


RFC 4291 由RFC 5952 更新,A Recommendation for IPv6 Address Text Representation进一步限制了第4.1 节中的正确表示。将 16 位字段中的前导零处理为无前导零:

4.1。处理 16 位字段中的前导零

必须抑制前导零。例如,2001:0db8::0001 是不可接受的,必须表示为 2001:db8::1。单个 16 位 0000 字段必须表示为 0。

RFC 5952 还要求压缩格式,其中多个连续的 16 位字段必须压缩为::

4.2. “::“ 用法

4.2.1。尽可能缩短

必须最大限度地使用符号“::”。例如,2001:db8:0:0:0:0:2:1 必须缩短为 2001:db8::2:1。同样,2001:db8::0:1 也是不可接受的,因为符号“::”可以用来生成更短的表示 2001:db8::1。

4.2.2. 处理一个 16 位 0 字段

符号“::”不得仅用于缩短一个 16 位 0 字段。例如,表示 2001:db8:0:1:1:1:1:1 是正确的,但 2001:db8::1:1:1:1:1 是不正确的。

4.2.3。“::”的放置选择

当在“::”的位置上有替代选择时,必须缩短最长的连续 16 位 0 字段(即,在 2001 年缩短具有三个连续零字段的序列:0:0:1: 0:0:0:1)。当连续的 16 位 0 字段的长度相等时(即 2001:db8:0:0:1:0:0:1),必须缩短第一个零位序列。例如,2001:db8::1:0:0:1 是正确的表示。

基本上,RFC 5952 还要求您接受任何有效的 RFC 4291 格式,但您应该只输出任何 RFC 5952 格式的 IPv6 文本表示:

  1. IPv6 文本表示的建议

    本节介绍了 IPv6 地址的规范文本表示格式的建议。本文档中的建议完全符合 [RFC4291],由各种操作系统实现,并且对人类友好。在生成要表示为文本的地址时,系统应遵循本节中的建议,但所有实现必须接受并能够处理任何合法的 [RFC4291] 格式。建议人们在拼写地址时也遵循这些建议。


推荐阅读