Inet6Address 对无效的 IPv6 地址有效

Inet6Address valid for invalid IPv6 Address

我正在使用 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;
    }
}

不幸的是,上述方法 returns 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 中是否存在 bug?

查看源代码,它看起来像是将字符串分解为字符,然后对每个字符进行位操作以将位添加到最终结果,然后左移 4 位并继续直到它命中一个: 或者结果超过 0xFFFF。 (http://www.docjar.com/html/api/sun/net/util/IPAddressUtil.java.html 第 170 行到第 180 行)。由于字符全为零,显然它永远不会超过 0xFFFF,因此它永远不会达到该限制。

我还阅读了 RFC2373 并说前导零是可选的,但它没有明确限制允许的数量。我会说这是一个错误,但(恕我直言)仅适用于迂腐的人。

根据有关 IPv6 地址的有效文本表示的最新 RFC,您遇到了一个错误,或者对 IPv6 地址文本表示的解释不佳。 IPv6 地址架构的最新 RFC 是 RFC 4291, IP Version 6 Addressing Architecture. That RFC has Section 2.2. Text Representation of Addresses 说(注意限制是四个十六进制数字):

2.2. Text Representation of Addresses

There are three conventional forms for representing IPv6 addresses as text strings:

  1. The preferred form is x:x:x:x:x:x:x:x, where the 'x's are one to four hexadecimal digits of the eight 16-bit pieces of the address. Examples:

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

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

    Note that it is not necessary to write the leading zeros in an individual field, but there must be at least one numeral in every field (except for the case described in 2.).

  2. Due to some methods of allocating certain styles of IPv6 addresses, it will be common for addresses to contain long strings of zero bits. In order to make writing addresses containing zero bits easier, a special syntax is available to compress the zeros. The use of "::" indicates one or more groups of 16 bits of zeros. The "::" can only appear once in an address. The "::" can also be used to compress leading or trailing zeros in an address.

    For example, the following addresses

    2001:DB8:0:0:8:800:200C:417A a unicast address FF01:0:0:0:0:0:0:101 a multicast address 0:0:0:0:0:0:0:1 the loopback address 0:0:0:0:0:0:0:0 the unspecified address

    may be represented as

    2001:DB8::8:800:200C:417A a unicast address FF01::101 a multicast address ::1 the loopback address :: the unspecified address

  3. An alternative form that is sometimes more convenient when dealing with a mixed environment of IPv4 and IPv6 nodes is x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values of the six high-order 16-bit pieces of the address, and the 'd's are the decimal values of the four low-order 8-bit pieces of the address (standard IPv4 representation). Examples:

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

    or in compressed form:

    ::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, which further limited a proper representation in Section 4.1. Handling Leading Zeros 在 16 位字段中更新为无前导零:

4.1. Handling Leading Zeros in a 16-Bit Field

Leading zeros MUST be suppressed. For example, 2001:0db8::0001 is not acceptable and must be represented as 2001:db8::1. A single 16-bit 0000 field MUST be represented as 0.

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

4.2. "::" Usage

4.2.1. Shorten as Much as Possible

The use of the symbol "::" MUST be used to its maximum capability. For example, 2001:db8:0:0:0:0:2:1 must be shortened to 2001:db8::2:1. Likewise, 2001:db8::0:1 is not acceptable, because the symbol "::" could have been used to produce a shorter representation 2001:db8::1.

4.2.2. Handling One 16-Bit 0 Field

The symbol "::" MUST NOT be used to shorten just one 16-bit 0 field. For example, the representation 2001:db8:0:1:1:1:1:1 is correct, but 2001:db8::1:1:1:1:1 is not correct.

4.2.3. Choice in Placement of "::"

When there is an alternative choice in the placement of a "::", the longest run of consecutive 16-bit 0 fields MUST be shortened (i.e., the sequence with three consecutive zero fields is shortened in 2001: 0:0:1:0:0:0:1). When the length of the consecutive 16-bit 0 fields are equal (i.e., 2001:db8:0:0:1:0:0:1), the first sequence of zero bits MUST be shortened. For example, 2001:db8::1:0:0:1 is correct representation.

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

  1. A Recommendation for IPv6 Text Representation

    A recommendation for a canonical text representation format of IPv6 addresses is presented in this section. The recommendation in this document is one that complies fully with [RFC4291], is implemented by various operating systems, and is human friendly. The recommendation in this section SHOULD be followed by systems when generating an address to be represented as text, but all implementations MUST accept and be able to handle any legitimate [RFC4291] format. It is advised that humans also follow these recommendations when spelling an address.

我检查了 class java.net.Inet6Address 的文档,它说只考虑了 rfc2373。这意味着 API 已过时,必须升级以考虑 IETF 对 IPv6 文本表示的最新建议。