Java中的IPv4/IPv6网络计算和验证?

11

我正在寻找一个与Net_IPv4Net_IPv6 相似的Java包。它需要能够执行以下操作:

  • 验证地址是否有效(例如,127.0.0.1 是有效的,而 127.0.0.257 则无效)
  • 返回地址是否包含在子网内(例如,127.0.0.11 在 127.0.0.0/28 中)
  • 返回给定子网的广播地址(例如,对于 127.0.0.0/28,它是 127.0.0.15)

如果它还能:

  • 按顺序返回子网中的地址列表
  • 对地址列表进行排序

那就再好不过了。

我可能可以编写一个可执行所有这些操作的包,但如果有人已经费力地完成并且很可能做得更好,我会使用它。有没有这样的包或可以执行所有这些操作的包?由于我们正在扩展到 IPv6,因此如果可能的话,它需要同时适用于 IPv4 和 IPv6。

非常感谢任何帮助。

5个回答

8
也许CIDRUtils可以帮助你。它可以将CIDR表示法转换为IP范围。
免责声明:我是CIDRUtils的作者。

感谢您发布答案!请务必仔细阅读有关自我推广的FAQ。还请注意,每次链接到您自己的网站/产品时,必须发布免责声明。 - Andrew Barber
@AndrewBarber 谢谢。我之前不知道这个。我只是想帮助其他可能遇到同样问题的人。无论如何,我会加上免责声明。 - Edin Dazdarevic

6

IPAddress Java库以多态方式支持IPv4和IPv6,包括子网。该链接提供了javadoc。免责声明:我是项目经理。

所有你列出的用例都能透明地支持IPv4和IPv6。换句话说,与大多数其他工具不同,下面的代码会对输入字符串中的IPv4或IPv6起作用。

验证地址是否有效

    String str = "::1";
    IPAddressString addrString = new IPAddressString(str);
    try {
         IPAddress addr = addrString.toAddress();
         ...
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }

判断IP地址是否在子网中

    String str = "1::1";
    String subnetStr = "1::/64";
    IPAddressString addrString = new IPAddressString(str);
    IPAddressString subnetString = new IPAddressString(subnetStr);
    try {
         IPAddress addr = addrString.toAddress();
         IPAddress subnet = subnetString.toAddress();
         boolean isContained = subnet.contains(addr); //true in this case
         ...
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }

返回给定子网的广播地址。
    String subnetStr = "127.0.0.0/28";
    IPAddressString subnetString = new IPAddressString(subnetStr);
    try {
         IPAddress subnet = subnetString.toAddress();
         IPAddress broadcastAddr = subnet.getUpper();
         ...
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }

返回按顺序排列的子网地址列表。
    String subnetStr = "127.0.0.0/28";
    IPAddressString subnetString = new IPAddressString(subnetStr);
    try {
         IPAddress subnet = subnetString.toAddress();
         for(IPAddress addr : subnet.getIterable()) {
             ...
         }
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }

对地址列表进行排序

    List<IPAddressString> addrs; 
    Collections.sort(addrs); //IPAddressString implements Comparable
      

获取子网网络集和地址列表(响应AhmedRana):

    IPAddress subnet = new IPAddressString("192.168.0.0/28").getAddress();
    IPAddress newSubnets = subnet.adjustPrefixLength(1, false);
    System.out.println(newSubnets); //192.168.0.0-8/29
    HashSet<IPAddress> subnetSet = new HashSet<IPAddress>();
    ArrayList<IPAddress> addrList = new ArrayList<IPAddress>();
    for(IPAddress addr : newSubnets.getIterable()) {
        subnetSet.add(addr.toPrefixBlock());
        addrList.add(addr);
    }
    System.out.println(subnetSet);//[192.168.0.0/29, 192.168.0.8/29]
        
    System.out.println(addrList);
                //[192.168.0.0/29, 192.168.0.1/29, 192.168.0.2/29,
                //192.168.0.3/29, 192.168.0.4/29, 192.168.0.5/29,
                //192.168.0.6/29, 192.168.0.7/29, 192.168.0.8/29,
                //192.168.0.9/29, 192.168.0.10/29, 192.168.0.11/29,
                //192.168.0.12/29, 192.168.0.13/29, 192.168.0.14/29,
                //192.168.0.15/29]

可能会有许多地址。获取新子网列表的更有效方法是使用前缀块迭代器,该迭代器遍历前缀块子网,如下所示:

    IPAddress subnet = new IPAddressString("192.168.0.0/28").getAddress();
    IPAddress newSubnets = subnet.adjustPrefixLength(1, false);
    System.out.println(newSubnets); // 192.168.0.0-8/29
    Iterator<? extends IPAddress> iterator = newSubnets.prefixBlockIterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
    // 192.168.0.0/29
    // 192.168.0.8/29

不客气。是的,它可以做这些事情,我已经更新了你的示例代码答案,在你的示例中产生了两个子网,每个子网都有8个地址。然而,在回答你的问题时,我现在看到虽然它可以很容易和高效地获取子网列表,但对于大型子网来说,将它们作为列表或集合获取并不高效(需要迭代许多地址),所以我会添加一个前缀块迭代器方法来更有效地完成这项工作,该方法只需迭代子网网络列表即可。 - Sean F
谢谢Sean,这个库的任何版本都与JRE 1.5兼容吗(或者有没有办法使其与1.5兼容)?我只对IPv4感兴趣,并且我有一个限制,它必须在安装了Java 5的系统上运行。 - AhmedRana
@AhmedRana 你好,最新版本的IPAddress使用了很多lambda表达式(在Java 8中添加),因此将最新版本的IPAddress移植到其他版本可能不容易。 IPAddress 1.0.0版本适用于Java 7,但是该版本缺少我后来添加到库中的一些功能。虽然Java 7没有添加太多内容,因此将该版本与Java 6配合使用可能很容易,但是Java 6是Java的一个重大版本,因此很难说IPAddress 1.0.0版本是否可以轻松地与Java 5配合使用。 - Sean F
我建议您可以拿取版本1.0.0的代码,看看能否在Java 5上运行,然后如果您想要使用最新的IPAddress中的某些功能,则只需移植这些功能即可。将最新版本的IPAddress移植到Java 5可能需要很多工作,主要是由于代码中的lambda函数。 - Sean F
或者,您可以从最新版本的IPAddress开始,但仅将Java 5端口到您希望使用的内容。任何lambda函数都可以替换为具有单个方法的匿名类实例。 - Sean F
显示剩余5条评论

5

这只适用于IPv4,但是SubnetUtils类是Commons Net的一部分,具有您正在寻找的功能。基于此,您可以编写一个IPv6版本并将其贡献给该项目! :)


4
我是commons-ip-math的主要贡献者,这是一个开源Java库,为处理IPv4、IPv6和AS号码的最常见计算提供了丰富的API。尽管它最近才开源,但在RIPE NCC内部经过多年的实战检验。以下是您可以使用它的方法。
(所有示例都使用类似的IPv6和AS号码语法。只需使用Ipv6、Ipv6Range、Asn和AsnRange类即可)。
  • 验证地址是否有效(例如,127.0.0.1是有效的,而127.0.0.257则无效)
Ipv4.parse("127.0.0.1");     // IPv4 representation of "127.0.0.1"
Ipv4.parse("127.0.0.257");   // IllegalArgumentException
  • 判断一个地址是否在子网内(例如,127.0.0.11是否在127.0.0.0/28中)
Ipv4Range.parse("127.0.0.0/28").contains(Ipv4.parse("127.0.0.11"));  //true  

给定子网,返回广播地址(例如,对于127.0.0.0/28,它是127.0.0.15)。
Ipv4Range.parse("127.0.0.0/28").start().upperBoundForPrefix(28)  // 127.0.0.15

返回按顺序排列的子网地址列表。
// Range types are Iterable
for (Ipv4 ipv4 : Ipv4Range.parse("127.0.0.0/30")) {
  System.out.println(ipv4);
}
// Will print:
127.0.0.0
127.0.0.1
127.0.0.2
127.0.0.3
  • 对地址列表进行排序

虽然该库为范围类型(例如比较子网的大小)提供了比较器,但是没有针对单个地址的比较器。但是,编写自己的比较器非常简单,因为Ipv4、IPv6和ASN类型实现了Comparable接口:

List<Ipv4> list = new ArrayList<Ipv4>();
list.add(Ipv4.of("0.0.0.3"));
list.add(Ipv4.of("0.0.0.4"));
list.add(Ipv4.of("0.0.0.2"));
list.add(Ipv4.of("0.0.0.1"));
Collections.sort(list, new Comparator<Ipv4>() {
    @Override
    public int compare(Ipv4 left, Ipv4 right) {
        return left.compareTo(right);
    }
});
System.out.println(list);
// Will print:
[0.0.0.1, 0.0.0.2, 0.0.0.3, 0.0.0.4]

@Pawel 我已经创建了 https://github.com/jgonian/commons-ip-math/issues/2 来进行调查。 - jgonian
1
我只是在尝试寻找 sun.net.util.IPAddressUtil 的替代品 - 在切换到 Java 8 后,我的一些测试失败了。我的测试用例来自于:http://download.dartware.com/thirdparty/test-ipv6-regex.pl(这应该会有所帮助)。 - Pawel
1
"1111:2222:3333:4444:5555:6666::1.2.3.4" 不应该是IPv6,但库将其解析为 "1111:2222:3333:4444:5555:6666:102:304"。 - Pawel
谢谢你发现了这个问题。我会在 https://github.com/jgonian/commons-ip-math/issues/4 中修复它。 - jgonian
显示剩余2条评论

0

InetAddress类及其相关子类是一个非常好的起点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接