5

I've been trying to convert the following from Python to node.js. It's a simply program that uses regex to check if an IP address is Public or Private:

import re

def is_private_ip(ip):
    """
    Returns `True` if the `ip` parameter is a private network address.
    """
    c = re.compile('(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)')
    if c.match(ip): return True
    return False

print is_private_ip('192.168.0.1') # True
print is_private_ip('8.8.8.8') # False
print is_private_ip('109.231.231.221') # False

I implemented it in Javascript like this:

var localIp = new RegExp(/(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/);
console.log('192.168.0.1'.match(localIp));
console.log('8.8.8.8'.match(localIp));
console.log('109.231.231.221'.match(localIp));

Which gives me the following output:

[ '192.168.',
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  '192.168.',
  index: 0,
  input: '192.168.0.1' ]
null
null

It seems to me like it works (not even sure tbh). The two IPs that should be public are returning null so I'm guessing that's right. I don't understand the output of the other match though? I've not been able to find out what it means

Juicy
  • 11,840
  • 35
  • 123
  • 212

5 Answers5

1

.match() gives you the number of matches possible in your String. Maybe what you're looking for is .test() method.

You need to modify the code like this:

var localIp = new RegExp(/(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/);
console.log(localIp.test('192.168.0.1'));
console.log(localIp.test('8.8.8.8'));
console.log(localIp.test('109.231.231.221'));

You may refer here for more details regarding the match method: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/match

ShivangiBilora
  • 2,912
  • 4
  • 20
  • 27
1

String.prototype.match():

If the regular expression does not include the g flag, returns the same result as RegExp.exec(). The returned Array has an extra input property, which contains the original string that was parsed. In addition, it has an index property, which represents the zero-based index of the match in the string.

RegExp.prototype.exec():

The returned array has the matched text as the first item, and then one item for each capturing parenthesis that matched containing the text that was captured.

If the match fails, the exec() method returns null.

Maybe you want to use RegExp.prototype.test() instead:

var localIp = new RegExp(/(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/);
console.log(localIp.test('192.168.0.1'));      // => true
console.log(localIp.test('8.8.8.8'));          // => false
console.log(localIp.test('109.231.231.221'));  // => false
Community
  • 1
  • 1
Johan Karlsson
  • 6,419
  • 1
  • 19
  • 28
1

You are using the String.prototype.match-method. According to the documentation, it returns "An Array containing the matched results or null if there were no matches."

In Javascript, an Array is truthy and null is falsy. This means that the following check would indeed correctly test if a string is a local IP:

if(someIpString.match(localIp)) {
  // it is a local IP
}
else {
  // it is not a local IP
}

What you are seeing in the array is the different parts of the original string that were matched by matching groups in the regular expression. The null values are the matches for groups that are not present, which you have plenty of.

But I think you can go a step further. If you want to simply check if a string matches the regular expression, I would recommend RegExp.prototype.test. This method returns a boolean (true|false), so you don't have to rely on truthy- or falsy-ness:

if(localIp.test(someIpString)) {
  // it is a local IP
}
else {
  // it is not a local IP
}
Niels Abildgaard
  • 2,662
  • 3
  • 24
  • 32
1
var localIp = new RegExp(/(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/);

console.log('192.168.0.1'.match(localIp));

gives you the output:

[ '192.168.',
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  '192.168.']

That means:

  • '192.168.' that is the match of the regex on this string. the only one
  • undefined is the match for the first group in your regex: (^127\.0\.0\.1)
  • undefined for the group: (^10\.)
  • undefined for the group: (^172\.1[6-9]\.)
  • undefined for the group: (^172\.2[0-9]\.)
  • undefined for the group: (^172\.3[0-1]\.)
  • '192.168.' for the group: (^192\.168\.)

thats because of the parenthesis, each one of them giving a match (or undefined), plus the match that the match() function returns.

Salvatorelab
  • 11,614
  • 6
  • 53
  • 80
1

You don't need to use match groups, unless you want to capture the matching portion of the ip address, but that's not necessary in your case. In Javascript you can use this regex pattern (note no match groups):

var localIp = new RegExp(/^127\.0\.0\.1|^10\.|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-1]\.|^192\.168\./);

And then use it like this:

console.log('192.168.0.1'.match(localIp) != null);
console.log('8.8.8.8'.match(localIp) != null);
console.log('109.231.231.221'.match(localIp) != null);

Or, even better, use RegEx.test():

console.log(localIp.test('192.168.0.1'));

Similarly for Python, the match groups are not required.

One other thing worth noting is that your pattern will match invalid IP addresses, e.g. 10.bad.ip.address will be detected as a private IP address. Not a problem if are validating IP addresses elsewhere in your application, but you might want to tighten it up.

mhawke
  • 84,695
  • 9
  • 117
  • 138