Either with PHP or a RegExp (or both), how do I match a range of IP addresses?
Sample Incoming IPs
10.210.12.12
10.253.12.12
10.210.12.254
10.210.12.95
10.210.12.60
Sample Ranges
10.210.12.0/24
10.210.12.0/16
10.210.*.*
10.*.*.*
I know that I can do this:
?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)
...but it doesn't take ranges into account. It merely lets you match an incoming number to see if it's an IP address where each octet is 0-255.
EDIT:
There's also this function that I found in a comment at php.net on the ip2long function.
function ip_in_network($ip, $net_addr, $net_mask){
if($net_mask <= 0){ return false; }
$ip_binary_string = sprintf("%032b",ip2long($ip));
$net_binary_string = sprintf("%032b",ip2long($net_addr));
return (substr_compare($ip_binary_string,$net_binary_string,0,$net_mask) === 0);
}
ip_in_network("192.168.2.1","192.168.2.0",24); //true
ip_in_network("192.168.6.93","192.168.0.0",16); //true
ip_in_network("1.6.6.6","128.168.2.0",1); //false
It's short and sweet, but doesn't match the asterisk situation. I also don't know if it's entirely accurate because it returns a true result on this when I thought it would be a false:
echo ip_in_network("192.168.2.1","192.167.0.0",1);
...but perhaps I misunderstand what the /1 would be. Perhaps I needed to use /24.
Regex really doesn't sound like the right tool to deal with subnet masks (at least not in decimal). It can be done, but it will be ugly.
I strongly suggest parsing the string into 4 integers, combining to a 32-bit int, and then using standard bitwise operations (basically a bitwise-AND, and then a comparison).
Use strpos to match them as strings.
Use this library: https://github.com/S1lentium/IPTools
I've improved on the above example (I have a netmask with /29 so it doesn't work).
If you want to see it in action, add this:
Run it with something like this:
I adapted an answer from php.net and made it better.
This results with:
Convert to 32 bit unsigned and use boolean/bitwise operations.
For example, convert 192.168.25.1 to 0xC0A81901.
Then, you can see if it matches the mask 192.168.25/24 by converting the dotted-decimal portion of the mask, i.e., 0xC0A81900, and creating a 24 bit mask, i.e., 0xFFFFFF00.
Perform a bitwise AND between the address in question and the mask and compare to the dotted decimal portion of the mask specification. For example,
I don't know PHP, but google tells me that PHP has inet_pton(), which is what I would use in C to perform the conversion from dotted-decimal to n-bit unsigned. See http://php.net/manual/en/function.inet-pton.php