tags:

views:

980

answers:

4

I'm looking for quick/simple/(maybe built in that i never noticed before), method for matching a given IP4 dotted quad IP to a CIDR notation mask.

I have a bunch of IPs I need to see if they match a range of IPs.

example:

$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');

foreach($ips as $IP)
{
    if( cidr_match($IP, '10.2.0.0/16') == true )
    { print "your in the 10.2 subnet\n"; }
}

solve for cidr_match()

it doesnt really have to be simple, but fast would be good. anything that uses only built in/common functions is a bonus (as i'm likely to get one person to show me something in pear that does this, but i cant depend on pear or that package being installed where my code is deployed)

+5  A: 

If only using IPv4:

  • use ip2long() to convert the IPs and the subnet range into long integers
  • convert the /xx into a subnet mask
  • do a bitwise 'and' (i.e. ip & mask)' and check that that 'result = subnet'

something like this should work:

function cidr_match($ip, $range)
{
    list ($subnet, $bits) = split('/', $range);
    $ip = ip2long($ip);
    $subnet = ip2long($subnet);
    $mask = -1 << (32 - $bits);
    $subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
    return ($ip & $mask) == $subnet;
}
Alnitak
perhaps if you posted your C# version we might be able to figure out why?
Alnitak
(the PHP code above _does_ work for the example you gave)
Alnitak
+1  A: 
function cidr_match($ipStr, $cidrStr) {
  $ip = ip2long($ipStr);
  $cidrArr = split('/',$cidrStr);
  $maskIP = ip2long($cidrArr[0]);
  $maskBits = 32 - $cidrArr[1];
  return (($ip>>$maskBits) == ($maskIP>>$maskBits));
}
vartec
A: 

I have been looking everywhere for this EXACT function in C++, can anyone show this in C++?

you might want to try asking a new question, and tagging it with C++ as the right people are more likely to see it.
Uberfuzzy
A: 

I want to have you look at my few lines. The examples that people suggested before me don't seem to work. One reason being, as far as I understand it, is that CIDR mask bits are binary numbers, so the bit shift must be done on a binary number. I have tried converting the long IP's into binaries, but ran into a max binary number limit. OK, here my few lines ... I await your comments.

function cidr_match($ipStr, $cidrStr) {

$ipStr = explode('.', $ipStr);
foreach ($ipStr as $key => $val) {
 $ipStr[$key] = str_pad(decbin($val), 8, '0', STR_PAD_LEFT);
 }
$ip = '';
foreach ($ipStr as $binval) {
 $ip = $ip . $binval;
 }

$cidrArr = explode('/',$cidrStr);

$maskIP = explode('.', $cidrArr[0]);
foreach ($maskIP as $key => $val) {
 $maskIP[$key] = str_pad(decbin($val), 8, '0', STR_PAD_LEFT);
 }
$maskIP = '';
foreach ($ipStr as $binval) {
 $maskIP = $maskIP . $binval;
 }
$maskBits = 32 - $cidrArr[1];
return (($ip>>$maskBits) == ($maskIP>>$maskBits)); 
}