Find Whether an IP Address Is in the Specified Range or Not in Java – 在Java中查找一个IP地址是否在指定的范围内

最后修改: 2021年 7月 25日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll discuss how to find whether an IP address is in a given range or not using Java. For this problem, we’ll consider all the given IP addresses are valid IPv4 (Internet Protocol Version 4) and IPv6 (Internet Protocol Version 6) addresses throughout the article.

在本教程中,我们将讨论如何使用 Java 查找IP地址是否在指定范围内。对于这个问题,我们将在文章中考虑所有给定的IP地址都是有效的IPv4(Internet协议版本4)和IPv6(Internet协议版本6)地址。

2. Introduction to the Problem

2.对问题的介绍

Given an input IP address along with the two other IP addresses as the range (from and to). We should be able to determine whether the input IP address is in the given range or not.

给出一个输入的IP地址,以及另外两个IP地址作为范围(从和到)。我们应该能够确定输入的IP地址是否在给定范围内

For Example:

比如说。

  • Input = 192.220.3.0, Range between 192.210.0.0 and 192.255.0.0
    Output = true
  • Input = 192.200.0.0, Range between 192.210.0.0 and 192.255.0.0
    Output = false

Now, let’s look at the different ways to check the given IP address is in range or not, using various Java libraries.

现在,让我们看看使用各种Java库检查给定IP地址是否在范围内的不同方法。

3. IPAddress Library

3.IPAddress库

The IPAddress library, written by Sean C Foley, supports handling both IPv4 and IPv6 addresses for a wide range of use cases. It is important to note that this library requires at least Java 8 to work.

由 Sean C Foley 编写的IPAddress库支持处理 IPv4 和 IPv6 地址,用于广泛的使用情况需要注意的是,这个库至少需要Java 8才能工作。

Setting up this library is straightforward. We need to add the ipaddress dependency to our pom.xml:

设置这个库是很简单的。我们需要将ipaddress 依赖关系添加到我们的 pom.xml 中。

<dependency>
    <groupId>com.github.seancfoley</groupId>
    <artifactId>ipaddress</artifactId>
    <version>5.3.3</version>
</dependency>

It provides the following Java classes needed to solve our problem:

它提供了解决我们问题所需的以下Java类。

  • IPAddress, to hold the IP address as a Java instance
  • IPAddressString, to construct the IPAddress instance from the given IP as a string
  • IPAddressSeqRange, to represent an arbitrary range of IP addresses

Now, let’s look at the code for finding whether an IP address is in the given range by using the above classes:

现在,让我们看看通过使用上述类来寻找一个IP地址是否在给定范围内的代码。

public static boolean checkIPIsInGivenRange (String inputIP, String rangeStartIP, String rangeEndIP) 
  throws AddressStringException {
    IPAddress startIPAddress = new IPAddressString(rangeStartIP).getAddress();
    IPAddress endIPAddress = new IPAddressString(rangeEndIP).getAddress();
    IPAddressSeqRange ipRange = startIPAddress.toSequentialRange(endIPAddress);
    IPAddress inputIPAddress = new IPAddressString(inputIP).toAddress();

    return ipRange.contains(inputIPAddress);
}

The above code works for both IPv4 and IPv6 addresses. IPAddressString parameterized constructor takes an IP as a string to construct IPAddress instance. IPAddressString instance can be converted to IPAddress by using any of the following two methods:

上述代码对IPv4和IPv6地址都有效。IPAddressString参数化构造器将IP作为字符串来构造IPAddress实例。IPAddressString实例可以通过使用以下两种方法中的任何一种转换为IPAddress

  • toAddress()
  • getAddress()

The getAddress() method assumes the given IP is valid, but the toAddress() method validates the input once and throws AddressStringException if it is invalid. IPAddress class provides a toSequentialRange method that constructs IPAddressSeqRange instance using the beginning and ending IP range.

getAddress()方法假设给定的IP是有效的,但是toAddress()方法对输入进行一次验证,如果无效则抛出AddressStringExceptionIPAddress类提供了一个toSequentialRange方法,使用开始和结束的IP范围构建IPAddressSeqRange实例。

Let’s consider few unit cases which calls checkIPIsInGivenRange with IPv4 and IPv6 addresses:

让我们考虑几个单元案例,其中调用checkIPIsInGivenRange的IPv4和IPv6地址。

@Test
void givenIPv4Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPIsInGivenRange("192.220.3.0", "192.210.0.0", "192.255.0.0"));
}

@Test
void givenIPv4Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPIsInGivenRange("192.200.0.0", "192.210.0.0", "192.255.0.0"));
}

@Test
void givenIPv6Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPIsInGivenRange(
      "2001:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
}

@Test
void givenIPv6Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPIsInGivenRange(
      "2002:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
}

4. Commons IP Math

4.公用事业IP数学

Commons IP Math library provides classes for representing IPv4 and IPv6 addresses and ranges. It provides APIs for dealing with the most common operations, and in addition, it gives comparators and other utilities for working with IP ranges.

Commons IP Math库提供了用于表示IPv4和IPv6地址和范围的类。它提供了用于处理最常见操作的API,此外,它还提供了用于处理IP范围的比较器和其他实用工具。

We need to add the commons-ip-math dependency to our pom.xml:

我们需要将commons-ip-math依赖性添加到我们的 pom.xml 中。

<dependency>
    <groupId>com.github.jgonian</groupId>
    <artifactId>commons-ip-math</artifactId>
    <version>1.32</version>
</dependency>

4.1. For IPv4

4.1. 对于IPv4

The library provides Ipv4 and Ipv4Range classes for holding a single IP address and a range of addresses as instances, respectively. Now, let’s glance at the code sample which makes use of the aforementioned classes:

该库提供了Ipv4Ipv4Range类,分别用于保存单个IP地址和地址范围的实例。现在,让我们看一下使用上述类的代码示例。

public static boolean checkIPv4IsInRange (String inputIP, String rangeStartIP, String rangeEndIP) {
    Ipv4 startIPAddress = Ipv4.of(rangeStartIP);
    Ipv4 endIPAddress = Ipv4.of(rangeEndIP);
    Ipv4Range ipRange = Ipv4Range.from(startIPAddress).to(endIPAddress);
    Ipv4 inputIPAddress = Ipv4.of(inputIP);
    return ipRange.contains(inputIPAddress);
}

Ipv4 class provides a static method of() that takes the IP string to construct an Ipv4 instance. Ipv4Range class uses the builder design pattern to create its instance by using from() and to() methods to specify the range. Further, it provides the contains the () function to check for an IP address present in the specified range or not.

Ipv4类提供了一个静态方法of(),它接收IP字符串来构建一个Ipv4实例。Ipv4Range类使用builder设计模式,通过使用from()to()方法指定范围来创建其实例。此外,它还提供了contains the () 函数来检查指定范围内是否存在IP地址。

Now let’s run some tests against our function:

现在让我们针对我们的函数运行一些测试。

@Test
void givenIPv4Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPv4IsInRange("192.220.3.0", "192.210.0.0", "192.255.0.0"));
}

@Test
void givenIPv4Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPv4IsInRange("192.200.0.0", "192.210.0.0", "192.255.0.0"));
}

4.2. For IPv6

4.2. 对于IPv6

For IP version 6, the library provides the same classes and functions with a change in the version number from 4 → 6. The classes for version 6 are Ipv6 and Ipv6Range. 

对于IP版本6,该库提供了同样的类和函数,只是版本号从4改为6。版本6的类是Ipv6Ipv6Range。

Let’s peek at the code example for IP version 6 by utilizing the aforementioned classes:

让我们偷看一下利用上述类的IP版本6的代码例子。

public static boolean checkIPv6IsInRange (String inputIP, String rangeStartIP, String rangeEndIP) {
    Ipv6 startIPAddress = Ipv6.of(rangeStartIP);
    Ipv6 endIPAddress = Ipv6.of(rangeEndIP);
    Ipv6Range ipRange = Ipv6Range.from(startIPAddress).to(endIPAddress);
    Ipv6 inputIPAddress = Ipv6.of(inputIP);
    return ipRange.contains(inputIPAddress);
}

Now let’s run the unit tests to check our code:

现在让我们运行单元测试来检查我们的代码。

@Test
void givenIPv6Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPv6IsInRange(
      "2001:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
}

@Test
void givenIPv6Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPv6IsInRange(
      "2002:db8:85a3::8a03:a:b", "2001:db8:85a3::8a00:ff:ffff", "2001:db8:85a3::8a2e:370:7334"));
}

5. Using Java’s InetAddress Class for IPv4

5.使用Java的InetAddress类实现IPv4

IPv4 address is a sequence of four 1-byte values. Hence, it can be converted to a 32-bit integer. We can check if it falls under the given range.

IPv4地址是由四个1字节的值组成的序列。因此,它可以被转换为一个32位的整数。我们可以检查它是否落在给定的范围内。

Java’s InetAddress class represents an IP address and provides methods to get the IP for any given hostnames. An instance of InetAddress represents the IP address with its corresponding hostname.

Java的InetAddress类表示一个IP地址,并提供了为任何给定的主机名获取IP的方法。InetAddress的一个实例代表了具有相应主机名的IP地址。

Here’s the Java code to convert an IPv4 address into a long integer:

下面是将IPv4地址转换成长整数的Java代码。

long ipToLongInt (InetAddress ipAddress) {
    long resultIP = 0;
    byte[] ipAddressOctets = ipAddress.getAddress();

    for (byte octet : ipAddressOctets) {
        resultIP <<= 8;
        resultIP |= octet & 0xFF;
    }
    return resultIP;
}

By using the above method, let’s check for IP is in the range:

通过使用上述方法,让我们检查一下IP是否在这个范围内。

public static boolean checkIPv4IsInRangeByConvertingToInt (String inputIP, String rangeStartIP, String rangeEndIP) 
  throws UnknownHostException {
    long startIPAddress = ipToLongInt(InetAddress.getByName(rangeStartIP));
    long endIPAddress = ipToLongInt(InetAddress.getByName(rangeEndIP));
    long inputIPAddress = ipToLongInt(InetAddress.getByName(inputIP));

    return (inputIPAddress >= startIPAddress && inputIPAddress <= endIPAddress);
}

The getByName() method in InetAddress class takes either domain name or IP address as input and throws UnknownHostException if it’s invalid. Let’s check our code by running unit tests:

InetAddress类中的getByName()方法将域名或IP地址作为输入,如果无效则抛出UnknownHostException。让我们通过运行单元测试来检查我们的代码。

@Test
void givenIPv4Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPv4IsInRangeByConvertingToInt("192.220.3.0", "192.210.0.0", "192.255.0.0"));
}

@Test
void givenIPv4Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPv4IsInRangeByConvertingToInt("192.200.0.0", "192.210.0.0", "192.255.0.0"));
}

The above logic of converting an IP address to an integer also applies to IPv6, but it’s a 128-bit integer. Java language supports a maximum of 64-bit (long integer) in primitive data types. If we have to apply the above logic for version 6, we need to use either two long integers or BigInteger class for computations. But it would be a tedious process and also involves complex calculations.

上述将IP地址转换为整数的逻辑也适用于IPv6,但它是一个128位的整数。Java语言在原始数据类型中最多支持64位(长整数)。如果我们要将上述逻辑应用于版本6,我们需要使用两个长整数或BigInteger类进行计算。但这将是一个繁琐的过程,而且还涉及复杂的计算。

6. Java IPv6 Library

6.Java IPv6库

Java IPv6 library is written especially for IPv6 support in Java and to perform related operations on it. This library internally uses two long integers to store the IPv6 address. And it requires at least Java 6 to work.

Java IPv6库是专门为Java中的IPv6支持而编写的,并对其进行相关操作。该库内部使用两个长整数来存储IPv6地址。而且它至少需要Java 6才能工作。

We need the java-ipv6 dependency to be added to our pom.xml:

我们需要将java-ipv6依赖性添加到我们的 pom.xml 中。

<dependency>
    <groupId>com.googlecode.java-ipv6</groupId>
    <artifactId>java-ipv6</artifactId>
    <version>0.17</version>
</dependency>

The library provides various classes to operate with IPv6 addresses. Here are the two of them which help us to solve our problem:

该库提供了各种操作IPv6地址的类。下面是其中的两个类,它们帮助我们解决了问题。

  • IPv6Address, for expressing IPv6 as a Java instance
  • IPv6AddressRange, for representing a continuous range of consecutive IPv6 addresses

Let’s look at the code snippet that uses the above classes to check IP is in the given range:

让我们看一下使用上述类来检查IP是否在给定范围内的代码片段。

public static boolean checkIPv6IsInRangeByIPv6library (String inputIP, String rangeStartIP, String rangeEndIP) {
    IPv6Address startIPAddress = IPv6Address.fromString(rangeStartIP);
    IPv6Address endIPAddress = IPv6Address.fromString(rangeEndIP);
    IPv6AddressRange ipRange = IPv6AddressRange.fromFirstAndLast(startIPAddress, endIPAddress);
    IPv6Address inputIPAddress = IPv6Address.fromString(inputIP);
    return ipRange.contains(inputIPAddress);
}

IPv6Address class gives us various static functions to construct its instance:

IPv6Address类为我们提供了各种静态函数来构建它的实例。

  • fromString
  • fromInetAddress
  • fromBigInteger
  • fromByteArray
  • fromLongs

All the above methods are self-explanatory, which helps us to create an IPv6Address instance. IPv6AddressRange has a method named fromFirstAndLast() that takes two IP addresses as input. In addition, it provides a contains() method that takes an IPv6Address as a parameter and determines if it is present in the specified range or not.

所有上述方法都是不言自明的,这有助于我们创建一个IPv6Address实例。IPv6AddressRange有一个名为fromFirstAndLast()的方法,需要两个IP地址作为输入。此外,它还提供了一个contains()方法,将一个IPv6Address作为参数,并确定它是否存在于指定范围内。

By calling the above method we defined, let’s pass few sample inputs in our tests:

通过调用我们定义的上述方法,让我们在测试中传递一些样本输入。

@Test
void givenIPv6Addresses_whenIsInRange_thenReturnsTrue() throws Exception {
    assertTrue(IPWithGivenRangeCheck.checkIPv6IsInRangeByIPv6library(
      "fe80::226:2dff:fefa:dcba",
      "fe80::226:2dff:fefa:cd1f",
      "fe80::226:2dff:fefa:ffff"
    ));
}

@Test
void givenIPv6Addresses_whenIsNotInRange_thenReturnsFalse() throws Exception {
    assertFalse(IPWithGivenRangeCheck.checkIPv6IsInRangeByIPv6library(
      "2002:db8:85a3::8a03:a:b",
      "2001:db8:85a3::8a00:ff:ffff",
      "2001:db8:85a3::8a2e:370:7334"
    ));
}

7. Conclusion

7.结语

In this article, we examined how we can determine whether the given IP address (both v4 and v6) is in the specified range or not. With the help of various libraries, we analyzed checking the IP address presence without any complex logic and computations.

在这篇文章中,我们研究了如何确定给定的IP地址(包括v4和v6)是否在指定范围内。在各种库的帮助下,我们分析了在没有任何复杂逻辑和计算的情况下检查IP地址的存在。

As always, the code snippets of this article can be found over on GitHub.

一如既往,本文的代码片段可以在GitHub上找到