. The network mask (the "32" in "127.0.0.1/32") can be stored as a regular integer.
Now that we know how to transform (2130706433, 32) into (127.0.0.1, 32), how do we transform a range (213.144.132.248, 29) into human readable “213.144.132.248 to 213.144.132.254”? There we need to do some calculations of our own. If we have a network mask of /32, this means just one single host. A mask of /24 indicates 255 addresses, a /16 gives 65535 and a /8 gives 16777215 addresses. Yes, that has something to do with a number series involving a power of 2 and a “minus 1”, or to be more exact:
last IP = first IP + (2^(32-mask)) - 1
In MySQL, this would translate into the following for (213.144.132.248, 29):
select inet_ntoa(inet_aton('213.144.132.248') + (pow(2, (32-29))-1));
PHP
We can apply the same logic to PHP as well. In PHP the functions to convert between dotted quad and numeric are called long2ip and ip2long (see the PHP Reference). The translation for (213.144.132.248, 29) would thus be:
$lastip = $firstip + pow(2, (32-$mask)) - 1;
Note the peculiarity of the long numerical type in PHP and how to get around that – the german de.comp.lang.php.* FAQ shows a workaround: http://www.php-faq.de/q/q-code-ip-bereich.html
JavaScript / ECMAScript
Unfortunately, JavaScript does not contain something similar to “inet_aton” or “ip2long”, so we have to build our own:
function ip2long(ip) {
var ips = ip.split('.');
var iplong = 0;
with (Math) {
iplong = ips<sup><a href="#fn0">0</a></sup>*pow(256,3)+ips<sup><a href="#fn1">1</a></sup>*pow(256,2)+ips<sup><a href="#fn2">2</a></sup>*pow(256,1)+ips<sup><a href="#fn3">3</a></sup>*pow(256,0)
}
return iplong;
}
function long2ip(l) {
with (Math) {
var ip1 = floor(l/pow(256,3));
var ip2 = floor((l%pow(256,3))/pow(256,2));
var ip3 = floor(((l%pow(256,3))%pow(256,2))/pow(256,1));
var ip4 = floor((((l%pow(256,3))%pow(256,2))%pow(256,1))/pow(256,0));
}
return ip1 + '.' + ip2 + '.' + ip3 + '.' + ip4;
}
And the same power of two-thing to calculate the “last IP”:
function lastIP(ip, mask) {
return ip + (Math.pow(2, (32 - mask))-1);
}
Bonus points
Dealing with user input is maybe the single most important security issue in web applications. We must therefore take care that we only pass proper IP addresses to any backend function. The easiest way to do this is through a regular expression – after all, we know exactly how a dotted quad representation of an IP address should look like (four times up to three digits, separated by dots). Thus the (Perl style) regex should look like
/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
Validation of the numeric representation is of course trivial. In PHP:
if (!(is_numeric($ip)) { <b>kaboom</b>; }
It is a good idea to always trim() user input before validation or processing (if leading/trailing whitespace is not significant).