Using JavaScript how would I validate an IP address "x.x.x.x" is a valid IPV4 unicast address e.g. is not 0.0.0.0 or multicast (224.0.0.0 to 224.0.0.255, 224.0.1.0 to 238.255.255.255, 239.0.0.0 to 239.255.255.255)?
+3
A:
First you need to get it into a number, use this function:-
function IPToNumber(s)
{
var arr = s.split(".");
var n = 0
for (var i = 0; i < 4; i++)
{
n = n * 256
n += parseInt(arr[i],10)
}
return n;
}
Looking at you spec, whilst you seem to list a series of ranges those ranges appear to be contiguous to me, that is can be simplified to (224.0.0.0 to 239.255.255.255). Hence you can test with:-
var min = IPToNumber("224.0.0.0");
var max = IPToNumber("239.255.255.255");
var ipNum = IPToNumber(sTestIP);
var isValid = (ipNum != 0 && (ipNum < min || ipNum > max))
Note of course that without knowledge of the destinations subnet you can't tell whether the address is the network address or the broadcast address for that subnet.
AnthonyWJones
2009-10-01 13:36:06
Your use of `*` instead of bitwise operators means your numbers shouldn't be cast to `Int32` at any point - clever!
Alex Barrett
2009-10-01 13:48:41
Be careful of something like this, which is valid: 70.16.18.015. Your parseInt call might not treat everything as decimal.
Joel Coehoorn
2009-10-01 14:00:32
A quick test using 0.0.0.015 confirmed the bug. I fixed your code.
Joel Coehoorn
2009-10-01 14:06:09
Yeah... Those stupid octal strings. Who ever needs them anyway?
Ates Goral
2009-10-01 14:07:55
@Joel: Ouch! well spotted ;)
AnthonyWJones
2009-10-01 15:33:35
+2
A:
The dotted quad notation you're seeing is just that: a notation that makes it easier on human eyes. An IP Address is really a 32 bit integer. I suggest you convert your address to that integer and then just check that it's in a valid range (ie, > 0 for the first requirement).
To that end:
function dottedQuadToInt(ip)
{
var parts = ip.split('.', 4);
var result = 0, base = 1;
for (var i = 3;i>=0;i--)
{
//validation
if (parts[i].length == 0 || parts[i].length > 3) return -1;
var segment = parseInt(parts[i],10);
if (isNaN(segment) || segment<0 || segment > 255) return -1;
//compute next segment
result += base * segment;
base = base << 8;
}
return result;
}
and then:
function isValidIP(ip)
{
ip = dottedQuadToInt(ip);
if (ip <= 0) return false;
//mulitcast range:
if (ip >= 3758096384 && ip <= 4026531839) return false;
//alternate way to check multicast:
if (ip >= dottedQuadToInt('224.0.0.0') && ip <= dottedQuadToInt('239.255.255.255')) return false;
return true;
}
Joel Coehoorn
2009-10-01 13:37:10
Oh yes I see, I didn't spot you are shifting base not the value itself.
AnthonyWJones
2009-10-01 13:50:01
+1
A:
/**
* Converts an IPv4 address to a (signed) 32-bit integer.
*/
function parse_ipv4_address(str) {
var arr = str.split('.');
for (var i = 0, val = 0; i < 4; i++) {
val += parseInt(arr[i], 10) << (8 * (3 - i));
}
return val;
}
var min = parse_ipv4_address('224.0.0.0');
var max = parse_ipv4_address('239.255.255.255');
var myIp = parse_ipv4_address(myIpStr);
// because the values are signed ints, min and max will be
// negative and we need to reverse the comparison operators :(
if (myIp == 0 || (myIp <= min && myIp >= max)) {
// multicast!
}
Alex Barrett
2009-10-01 13:44:41
I like that 3 of us posted pretty much the exact same thing. I will vote you both up :)
Alex Barrett
2009-10-01 13:52:37