【问题标题】:How to check the IP range by java matcher regular expression如何通过 java matcher 正则表达式检查 IP 范围
【发布时间】:2015-05-26 05:11:57
【问题描述】:

我当前用于检查 ip 范围的正则表达式:178.2.1.1 to 178.2.1.254 如下:

178.2.1.1.([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])$

有没有其他更好的表达方式来检查。

【问题讨论】:

  • 定义“之间”。您指定的是一个上限,然后是一个下限。但是正则表达式是完全错误的工具。您应该只使用 IP 地址本身作为 32 位整数或字节数组,并以算术方式进行。
  • 给定的正则表达式与请求的范围完全不匹配。
  • “之间”是什么意思?第二个 ip - 从数字上讲 - 低于第一个。
  • 我想知道为什么,当有perfectly established way of dealing with IP ranges 时,人们仍然坚持使用正则表达式。例如,在 Java 中,您可以使用 Apache Commons implementation
  • @biziclop:文章表示前 i 位很重要。这里 2550 被排除在外(是的,我知道这些是特殊的),但是可以说,出于某种奇怪的原因,希望一个 IP 介于 178.2.8.14194.45.2.41 之间,你不能用这样的掩码执行此操作。

标签: java regex


【解决方案1】:

正则表达式

假设您想匹配178.2.1.1178.2.1.254 之间的所有IP 地址(使用178 而不是1),您可以使用以下正则表达式:

^178\.2\.1\.([1-9]\d?|1\d{2}|2[0-4]\d|25[0-4])$

删除最后一个1.,对点使用转义符 (\.) 并使用正则表达式前面的锚点 (^)。

使用库进行边界检查

但是一般来说还不够。例如,大多数 IP 解析器允许将 IP 指定为127.00.00.01 等。此外,不要忘记现在人们转向具有完全不同语法的 IPv6。您最好按照here 的描述,在Java 中解析InetAddress。如果它是 IPv4,那么您可以简单地执行绑定检查,就像部分描述的 here

String       s = "178.2.1.178";
Inet4Address a = (Inet4Address) InetAddress.getByName(s);
byte[]       b = a.getAddress();
int          ip = ((b[0] & 0xFF) << 24) |
                  ((b[1] & 0xFF) << 16) |
                  ((b[2] & 0xFF) << 8)  |
                  ((b[3] & 0xFF) << 0);
int low =  0xb2020101; //equivalent of 178.2.1.1
int high = 0xb20201fe; //equivalent of 178.2.1.254
if(low <= ip && ip <= high) {
    //matches bounds
} else {
    //doesn't match bounds
}

或者正如@IanMcLaird 建议的那样,最好使用 BigInteger:

BigInteger addr = new BigInteger(InetAddress.getByName("178.2.1.178").getAddress());
BigInteger low = new BigInteger(InetAddress.getByName("178.2.1.1").getAddress());
BigInteger high = new BigInteger(InetAddress.getByName("178.2.1.254").getAddress());
if(low.compareTo(addr) <= 0 && addr.compareTo(high) <= 0) {
    //in range
} else {
    //not in range
}

子网

请注意,您可以使用178.2.1.0/24 来描述您的IP 范围,因为.0.255 是特殊情况,这意味着最后一个字节不重要。在这种情况下,我们谈论的是一个子网,并且——正如@biziclop 所说——你可以使用these Apache utils

【讨论】:

  • 我想我会使用BigInteger 而不是int,因为它的好处是有一个合适的构造函数(不需要看起来很奇怪的位移运算符)并且的好处是能够以相同的逻辑处理 IPv6 地址。
  • @IanMcLaird:确实,感谢您的建议。此外,它允许更轻松地转换为 IPv6。更好?
【解决方案2】:

您需要小心“介于”,因为两个 IP 都可以有最小值/最大值。您可以执行以下操作:

/**
 * check if IP address match pattern
 * 
 * @param pattern
 *            *.*.*.* , 192.168.1.0-255 , *
 * @param address
 *            - 192.168.1.1
 *            address = 10.2.88.12  pattern = *.*.*.*   result: true
 *                address = 10.2.88.12  pattern = *   result: true
 *                address = 10.2.88.12  pattern = 10.2.88.12-13   result: true
 *                address = 10.2.88.12  pattern = 10.2.88.13-125   result: false
 * @return true if address match pattern
 */
public static boolean checkIPMatching(String pattern, String address)
{
    if (pattern.equals("*.*.*.*") || pattern.equals("*"))
      return true;

    String[] mask = pattern.split("\\.");
    String[] ip_address = address.split("\\.");
    for (int i = 0; i < mask.length; i++)
    {
      if (mask[i].equals("*") || mask[i].equals(ip_address[i]))
        continue;
      else if (mask[i].contains("-"))
      {
        byte min = Byte.parseByte(mask[i].split("-")[0]);
        byte max = Byte.parseByte(mask[i].split("-")[1]);
        byte ip = Byte.parseByte(ip_address[i]);
        if (ip < min || ip > max)
          return false;
      }
      else
        return false;
    }
    return true;
}

aion-emu package 的一部分)

【讨论】:

    【解决方案3】:

    The open-source IPAddress Java library 可以很容易地提供答案,如此代码示例所示。 免责声明:我是该库的项目经理。

    public static boolean check(String addressToCheck) {
        return new IPAddressString("178.2.1.1-254").getAddress().
            contains(new IPAddressString(addressToCheck).getAddress());
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 1970-01-01
      • 2012-12-23
      • 2013-07-14
      • 2018-09-13
      • 2011-05-26
      • 1970-01-01
      • 2013-04-10
      • 2013-04-29
      相关资源
      最近更新 更多