2

In order to distinguish internal and external users, I'm using java regular expressions within scriplet tags and the code is below:

String ipAddress  = request.getHeader("iv-remote-address");

String internalIPs = 
"166.41.8.X" + "|" +"12.16.X.X" + "|" +"12.22.X.X" + "|" +"132.23.X.X" + "|";

Pattern p = Pattern.compile("^(?:"+internalIPs.replaceAll("X", "(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])")+")$");

Matcher m = p.matcher(ipAddress);

if (m.matches())
{
    //print internal IP     
} else{
    //print external IP 
}   

If the input is 166.41.8.2, the IP address is correctly identified as internal IP if the input is 12.16.2.1 or 12.22.12.3, the IP address is not correctly identified as internal IP. I guess that has to do with matching pattern with 2 "X"s. Can anybody identify the issue with pattern matching? Or could recommend a best way of matching pattern of IP addresses?

neelmeg
  • 2,459
  • 6
  • 34
  • 46
  • Remember that a '.' is a single any character in a regex. You will need to escape those. http://www.regular-expressions.info/numericranges.html has some good examples for matching a particular numeric range. I would be tempted to take the addr to an array of bytes (or an int) and then do bitwise operations comparing the two. See also http://stackoverflow.com/questions/4256438/calculate-whether-an-ip-is-in-a-specified-range-in-java and http://stackoverflow.com/questions/220110/a-good-java-library-for-network-math –  May 08 '12 at 21:05

3 Answers3

3

2 corrections:

  1. period . should be escaped otherwise it means any character
  2. \\d in your replaceAll call needs to be doubly escaped since that eventually becomes your final regex.

Here is the working code:

String ipAddress  = "12.16.2.1";
String internalIPs = 
"166\\.41\\.8\\.X" + "|" +"12\\.16\\.X\\.X" + "|" +
"12\\.22\\.X\\.X" + "|" +"132\\.23\\.X\\.X" + "|";

Pattern p = Pattern.compile("^(?:"+internalIPs.replaceAll("X",
                            "(?:\\\\d{1,2}|1\\\\d{2}|2[0-4]\\\\d|25[0-5])")+")$");

//System.out.println(p.pattern());

Matcher m = p.matcher(ipAddress);
if (m.matches())
    System.out.println("print internal IP"); // gets printed  
else
    System.out.println("print external IP"); 

Alternative Option:

Since you are not really using any regex in the internalIPs.replaceAll call it is better to use String#replace method (which doesn't support regex) and then there would be no need for double-escaping. So just use like this:

Pattern p = Pattern.compile("^(?:" + internalIPs.replace("X",
                            "(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])")+")$");
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • @JamesMontagne: The way it was in OP's code `\\d{1,2}` would eventually become `d{1,2}` in the final regex OP is building. That's why it needs to be doubly escaped. – anubhava May 08 '12 at 21:06
  • Yes, I just thought that was a bit unclear, why the slashes would disappear entirely. But I removed my comment because after writing it, I'm not sure it was any more clear (or fully correct). – James Montagne May 08 '12 at 21:08
  • @JamesMontagne: Please also see my alternative option. Since OP's not really using any regex in `replaceAll` call, it is better to replace that with `replace` and save the hassle of double-escaping. – anubhava May 08 '12 at 21:12
  • 1
    Agreed, `replace` is a better way to go. But I found a good clarification on the double-escaping from the java6 docs. "Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string. Dollar signs may be treated as references to captured subsequences as described above, and backslashes are used to escape literal characters in the replacement string." So that's the reason behind the double escaping, the 2nd parameter of `replaceAll` is a bit funny. – James Montagne May 08 '12 at 21:15
1

I don know if this is the cause, but try changing the . in your internal IPs declaration to \.

. in regexp is used to match everything.

James Montagne
  • 77,516
  • 14
  • 110
  • 130
Rafael
  • 2,373
  • 4
  • 22
  • 28
1

I would suggest not to perform too complicated IP gymnastics with regexs.

"([0-9]{1,3}.){3}[0-9]{1,3})" for a general check is okay, then I would do an

"166.41.8.123".split ("\\.")

followed by Integer.parseInt and range checks or value comparison.

user unknown
  • 35,537
  • 11
  • 75
  • 121