Netmask class - parse, manipulate and lookup IP network blocks
| From: | Dennis S. Davidoff | Date: | Fri, 25 Jul 2003 06:44:01 +0000 |
| Subject: | Netmask class - parse, manipulate and lookup IP network blocks | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-18672@lists.php.net to get a copy of this message | ||
<?php
// Netmask class - parse, manipulate and lookup IP network blocks
// Copyright (C) 1998, 2001 David Muir Sharnoff <muir@idiom.com>
// Net::Netmask ported from Perl to PHP by Dennis S.Davidoff <null@1system.ru>
// TODO:
// Methods: hostmask, storeNetblock, deleteNetblock
// Functions: findNetblock, findOuterNetblock, findAllNetblock, cidrs2contiglists,
by_net_netmask_block
class Netmask
{
var $error, $IBASE, $BITS;
var $remembered = array();
var $netblock = array();
var $quadmask2bits = array();
var $imask2bits = array();
var $size2bits = array();
var $debug = true;
function init($net = '', $mask = '')
{
unset($this->error);
for ($i = 0; $i <= 32; $i++) {
$imask = $this->imask($i);
$this->imask2bits["$imask"] = $i;
$this->quadmask2bits[$this->int2quad($imask)] = $i;
$k = pow(2, (32-$i));
$size2bits["$k"] = $i;
}
if (preg_match("/^(\d+\.\d+\.\d+\.\d+)\/(\d+)$/", $net, $matched)) {
$base = $matched[1]; $bits = $matched[2];
} elseif (preg_match("/^(\d+\.\d+\.\d+\.\d+)[:\/](\d+\.\d+\.\d+\.\d+)$/", $net,
$matched)) {
$base = $matched[1]; $quadmask = $matched[2];
if (array_key_exists($quadmask, $this->quadmask2bits)) {
$bits = $this->quadmask2bits[$quadmask];
} else {
$this->error = "illegal netmask: $quadmask";
}
} elseif (
preg_match("/^\d+\.\d+\.\d+\.\d+$/", $net)
&& preg_match("/\d+\.\d+\.\d+\.\d+$/", $mask)
)
{
$base = $net;
if (array_key_exists($mask, $this->quadmask2bits)) {
$bits = $this->quadmask2bits[$mask];
} else {
$this->error = "illegal netmask: $mask";
}
} elseif (preg_match("/^\d+\.\d+\.\d+\.\d+$/", $net) &&
preg_match("/0x([a-z0-9]+)/", $mask, $matched)) {
$base = $net;
$imask = hexdec($matched[1]);
if (array_key_exists("$imask", $this->imask2bits)) {
$bits = $this->imask2bits["$imask"];
} else {
$this->error = "illegal netmask: $imask";
}
} elseif (preg_match("/^\d+\.\d+\.\d+\.\d+$/", $net) &&
empty($mask)) {
$base = $net; $bits = 32;
} elseif (preg_match("/^\d+\.\d+\.\d+$/", $net) && empty($mask)) {
$base = "$net.0"; $bits = 24;
} elseif (preg_match("/^\d+\.\d+$/", $net) && empty($mask)) {
$base = "$net.0.0"; $bits = 16;
} elseif (preg_match("/^\d+$/", $net) && empty($mask)) {
$base = "$net.0.0.0"; $bits = 8;
} elseif (preg_match("/^(\d+\.\d+\.\d+)\/(\d+)$/", $net, $matched)) {
$base = $matched[1] . ".0"; $bits = $matched[2];
} elseif (preg_match("/^(\d+\.\d+)\/(\d+)$/", $net, $matched)) {
$base = $matched[1] . ".0.0"; $bits = $matched[2];
} elseif ($net == 'default') {
$base = '0.0.0.0'; $bits = 0;
} elseif
(preg_match("/^(\d+\.\d+\.\d+\.\d+)\s*\-\s*(\d+\.\d+\.\d+\.\d+)$/", $net, $matched)) {
$ibase = $this->quad2int($matched[1]);
$end = $this->quad2int($matched[2]);
if ($ibase == false || $end == false)
$this->error = "illegal dotted quad: $net";
$diff = ($end == false ? 0 : $end) - ($ibase == false ? 0 : $ibase) + 1;
if (!array_key_exists("$diff", $size2bits) &&
empty($this->error))
$this->error = "could not find exact fit for $net";
else $bits = $size2bits{"$diff"};
} else {
$this->error = "could not parse $net";
if (!empty($mask)) $this->error .= " $mask";
}
if ($this->debug == true && !empty($this->error))
die($this->error);
if (!isset($ibase)) {
if (($ibase = $this->quad2int( isset($base) ? $base : 0)) == false
&& empty($this->error)) {
$this->error = "could not parse $net";
if (!empty($mask)) $this->error .= " $mask";
} else {
$ibase += 0;
$ibase = sprintf('%u', ($ibase &=
$this->imask($bits)));
}
}
$this->IBASE = $ibase + 0;
$this->BITS = $bits;
if ($this->debug == true && !empty($this->error))
die($this->error);
return empty($this->error) ? true : false;
}
function imask ($i) {
return pow(2, 32) - pow(2, (32 - $i));
}
function errstr () { return $this->error; }
function bits () { return $this->BITS; }
function base () { return $this->int2quad($this->IBASE); }
function size () { return pow(2, (32 - $this->BITS)); }
function next () { $this->int2quad($this->IBASE + $this->size()); }
function mask () { return $this->int2quad ( $this->imask($this->BITS)); }
function desc () { return $this->int2quad($this->IBASE).'/'.$this->BITS;
}
function int2quad ($n) { return implode('.', unpack('C4',
pack("N", $n))); }
function broadcast () { return $this->int2quad($this->IBASE + $this->size() - 1); }
function nth ($index = 1, $bitstep = 0) {
$size = $this->size();
$ibase = $this->IBASE;
if ($bitstep == 0) $bitstep = 32;
$increment = pow(2, (32-$bitstep));
$index *= $increment;
if ($index < 0) $index += $size;
if ($index < 0) return false;
if ($index >= $size) return false;
return $this->int2quad($ibase+$index);
}
function enumerate ($bitstep = 0) {
$size = $this->size();
$ibase = $this->IBASE;
if ($bitstep == 0) $bitstep = 32;
$increment = pow(2, (32-$bitstep));
for ($i = 0; $i < $size; $i += $increment) {
$array[] = $this->int2quad($ibase+$i);
}
return $array;
}
function inaddr () {
$ibase = $this->IBASE;
$blocks = intval($this->size()/256);
if ($blocks == 0)
return array(
implode('.', unpack('x/C3', pack("V",
$ibase))) . ".in-addr.arpa",
fmod($ibase, 256), fmod($ibase, 256) + $this->size() - 1
);
for ($i = 0; $i < $blocks; $i++) {
$array[] = array(implode('.', unpack('x/C3',
pack("V", $ibase + $i*256))) . ".in-addr.arpa", 0, 255);
}
return $array;
}
function quad2int ($ip) {
$bytes = split('\.', $ip);
if (count($bytes) == 4) {
for ($i = 0; $i < count($bytes); $i++)
if ($bytes[$i] > 255) return false;
else eval("\$oct$i = $bytes[$i];");
} else {
$this->error = "quad2int(): illegal ipaddr: $ip";
if ($this->debug == true && !empty($this->error))
die($this->error);
return false;
}
$assoc_array = unpack("Nipaddr", pack('C4', $oct0, $oct1, $oct2,
$oct3));
return sprintf('%u', $assoc_array['ipaddr']);
}
function imaxblock ($ibase, $tbit) {
while($tbit > 0) {
$im = $this->imask($tbit-1);
if ((sprintf('%u', $ibase & $im)) != $ibase) break;
$tbit--;
}
return $tbit;
}
function sort_by_ip_address ($array) {
if (is_array($array)) {
natsort($array); return $array;
} else return false;
}
function range2cidrlist ($startip, $endip) {
if (($start = $this->quad2int($startip)) == false) {
$this->error = "range2cidrlist(): illegal \$startip: $startip";
if ($this->debug == true && !empty($this->error))
die($this->error);
return false;
}
if (($end = $this->quad2int($endip)) == false) {
$this->error = "range2cidrlist(): illegal \$startip: $startip";
if ($this->debug == true && !empty($this->error))
die($this->error);
return false;
}
$start += 0; $end += 0;
if ($start > $end) {
$k = $end; $end = $start; $start = $k;
}
while($end >= $start) {
$maxsize = $this->imaxblock($start, 32);
$maxdiff = 32 - intval(log($end - $start + 1)/log(2));
if ($maxsize < $maxdiff) $maxsize = $maxdiff;
$array[] = $this->int2quad($start)."/$maxsize";
$start += pow(2, (32 - $maxsize));
}
return $array;
}
function match ($ipaddr) {
if (($i = $this->quad2int($ipaddr)) == false) {
$this->error = "match(): illegal ipaddr: $ipaddr";
if ($this->debug == true && !empty($this->error))
die($this->error);
return false;
}
$i += 0;
$imask = $this->imask($this->BITS);
if ((sprintf('%u',($i & $imask))) == $this->IBASE)
return (($i & ~$imask) || "0 ");
else
return 0;
}
}
?>