Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching an IP to a CIDR mask in PHP 5?

Tags:

php

cidr

I'm looking for quick/simple 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 "you're in the 10.2 subnet\n";      } } 

What would cidr_match() look like?

It doesn't 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 can't depend on pear or that package being installed where my code is deployed).

like image 662
Uberfuzzy Avatar asked Feb 27 '09 09:02

Uberfuzzy


People also ask

How do I find the subnet mask for an IP address with CIDR?

The process to determine the subnet mask for a CIDR address is straight forward. The number of bits in the network portion of the address are converted to 1s and right padded with 0s until there are 32 numbers. The sequence of numbers is then divided into 4 octets.

Does IP match CIDR?

A CIDR block of /0 would allow access to any IP address between 0.0. 0.0 and 255.255. 255.255, while a CIDR block of /32 would only allow access to the IP address that precedes it. Adding /8 after an IP address will block all IP addresses that do not match the first 8 bits, or first number, in the address included.

How do I find my CIDR notation for an IP address?

The CIDR number is typically preceded by a slash “/” and follows the IP address. For example, an IP address of 131.10. 55.70 with a subnet mask of 255.0. 0.0 (which has 8 network bits) would be represented as 131.10.

Is CIDR and subnet mask the same?

CIDR notation is really just shorthand for the subnet mask, and represents the number of bits available to the IP address. For instance, the /24 in 192.168. 0.101/24 is equivalent to the IP address 192.168. 0.101 and the subnet mask 255.255.


Video Answer


2 Answers

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) = explode('/', $range);     if ($bits === null) {         $bits = 32;     }     $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; } 
like image 164
Alnitak Avatar answered Sep 24 '22 20:09

Alnitak


In a similar situation, I ended up using symfony/http-foundation.

When using this package, your code would look like:

$ips = array('10.2.1.100', '10.2.1.101', '10.5.1.100', '1.2.3.4');  foreach($ips as $IP) {     if (\Symfony\Component\HttpFoundation\IpUtils::checkIp($IP, '10.2.0.0/16')) {         print "you're in the 10.2 subnet\n";     } } 

It also handles IPv6.

Link: https://packagist.org/packages/symfony/http-foundation

like image 32
Dávid Veszelovszki Avatar answered Sep 25 '22 20:09

Dávid Veszelovszki