2

My Current Regular Expression for checking the ip range between: 178.2.1.1 to 178.2.1.254 is as follow:

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

Is there any other better expression way to check that.

AKZap
  • 1,181
  • 6
  • 17
  • 31
  • 1
    Define 'between'. What you have specified is an upper limit followed by a lower limit. But regular expressions are entirely the wrong tool for this. You should just use the IP addresses themselves as 32-bit integers, or byte arrays, and do it arithmetically. – user207421 May 26 '15 at 06:19
  • 1
    The given regex totally doesn't match the requested range. – Willem Van Onsem May 27 '15 at 12:40
  • What do you mean with "between"? The second ip is - numerically speaking - lower than the first. – Willem Van Onsem May 27 '15 at 12:41
  • I wonder why, when there's a [perfectly established way of dealing with IP ranges](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation), people still insist on regular expressions. In Java you can use the [Apache Commons implementation](http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/util/SubnetUtils.html) for example. – biziclop May 27 '15 at 12:52
  • @biziclop: the articles means that the first *i* bits are significant. Here `255` and `0` are excluded (yeah I know these are special ones), but lets say one wishes an ip to be between `178.2.8.14` and `194.45.2.41` for some strange reason, you cannot perform this with such mask. – Willem Van Onsem May 27 '15 at 12:55
  • @biziclop Regex tend to be used for anything *but* what they are made for. – runDOSrun May 27 '15 at 12:55
  • @CommuSoft The range you specified corresponds to `178.2.8.14/31,178.2.8.16/28,178.2.8.32/29,178.2.8.40/31` in CIDR notation. But yes, with arbitrary ranges CIDR isn't that straightforward. – biziclop May 27 '15 at 13:41
  • @biziclop: I'm not convincted the comma is part of the standard. If one reads the specs on the Wiki page it says an IP address with a slash (`/`) and a routing prefix. Here you specify multiple CIDRs. Making checking computationally harder. – Willem Van Onsem May 27 '15 at 13:45
  • @CommuSoft Okay, my main point really was to not use regular expressions, and I think we agree on that. – biziclop May 27 '15 at 13:49
  • @biziclop: sure. I've also added your subnet suggestion in the answer. It was a valuable contribution. The only point is that CIDR is sometimes not expressive enough. – Willem Van Onsem May 27 '15 at 13:50

3 Answers3

5

Regular expression

Assuming you want to match all IP adresses between 178.2.1.1 and 178.2.1.254 (with 178 instead of 1), you can use the following regex:

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

Dropping the last 1., using escapes for the dots (\.) and using the anchor in the front of the regex (^).

Bounds checking with a library

But that will not suffice in general. Most IP parsers allow for instance to specify an IP as 127.00.00.01, etc. Furthermore don't forget that nowadays people move to IPv6 which has a completely different syntax. You better do the parsing to an InetAddress in Java as is described here. In case it is an IPv4, you can then simply perform bound checks, like is partly described 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
}

Or as @IanMcLaird suggests, one better uses a 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
}

Subnets

Please note you can describe the range of your IP with 178.2.1.0/24 since .0 and .255 are special cases, it means the last byte is not significant. In such case we're talking about a subnet and - as @biziclop says - you can use these Apache utils.

Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    I think I'd use a `BigInteger` instead of `int`, since it has the benefit of having an appropriate constructor (which won't require odd-looking bit-shifting operators) *and* has the benefit of being able to handle IPv6 addresses with the same logic. – Ian McLaird May 27 '15 at 13:03
  • @IanMcLaird: indeed, thanks for that suggestion. Furthermore it allows easier conversion towards IPv6. Better? – Willem Van Onsem May 27 '15 at 13:17
2

You need to be careful with "between" as both IPs can have min/max values. You can do something like:

/**
 * 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;
}

(Part of aion-emu package )

runDOSrun
  • 10,359
  • 7
  • 47
  • 57
0

The open-source IPAddress Java library can provide the answer rather easily, as shown in this code example. Disclaimer: I am the project manager of that library.

public static boolean check(String addressToCheck) {
    return new IPAddressString("178.2.1.1-254").getAddress().
        contains(new IPAddressString(addressToCheck).getAddress());
}
Sean F
  • 4,344
  • 16
  • 30