From 9acf5528b6508a28d7ff8f57495eb9c3e5af7990 Mon Sep 17 00:00:00 2001 From: paulr Date: Mon, 13 Sep 2010 16:25:09 +1000 Subject: [PATCH] add the issubnet and isconflicting code checks for ipv6 --- lib/ip.php | 154 +++++++++++++++++++++++++++++++++++++++----------- lib/www.php | 5 +- unittest/iptogmp.php | 21 +++++++ 3 files changed, 144 insertions(+), 36 deletions(-) create mode 100644 unittest/iptogmp.php diff --git a/lib/ip.php b/lib/ip.php index 585643c..3a31d0b 100644 --- a/lib/ip.php +++ b/lib/ip.php @@ -4,7 +4,7 @@ function ipversion($ip) { $ipv4 = ereg('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$', $ip); $ipv6 = ereg("^[0-9a-fA-F:]+$", $ip); - + error_log("ipversion, $ip, $ipv4, $ipv6"); if($ipv4 == 1) return 4; if($ipv6 == 1) return 6; @@ -16,21 +16,25 @@ function ipversion($ip) function ip6ToLongStr($ip) { if(ipversion($ip)!=6) return false; - + $pss = explode(":", $ip); $ns = count($pss); - + $nstr = ""; foreach($pss as $ele) { + echo "ele: $ele\n"; if($nstr != "") { $nstr .= ":"; + echo "add colon\n"; } - if(strlen($ele < 1)) { + if(strlen($ele)<1) { // this is where we pad 8-count of 0000: + echo "add pad count\n"; $pds = 8-$ns+1; for($i=0; $i < $pds; $i++) { - $nstr .= "0000"; + $nstr .= "0000:"; } + $nstr = rtrim($nstr, ":"); } else if(strlen($ele) < 4) { $nstr .= str_pad($ele, 4, "0", STR_PAD_LEFT); } else { @@ -43,26 +47,51 @@ function ip6ToLongStr($ip) // this function converts an ip address to a comparable integer // so we can bounds-check. // it returns an array of [firstnum][lastnum] -function ip6ToComp($ip, $mask) +// this is without a doubt one of the ugliest things i've ever done. +function ip6ToGmp($ip, $mask) { - if($ipversion($ip)!=6) return false; + if(ipversion($ip)!=6) return false; + + $ipone = ip::truncateNetwork($ip, $mask); + $iponeap = $ipone."::0"; + $rip = ip6ToLongStr($iponeap); - $rip = ip6ToLongStr($ip); + $riphex = "0x".str_replace(":", "", $rip); + // f**king ugly + $sns = 8-($mask / 16); + + $slt = $ipone; + for($i = 0; $i < $sns; $i++) { + $slt .= ":FFFF"; + } + + $endhex = "0x".str_replace(":", "", ip6ToLongStr($slt)); + + echo "$rip, $ipone, $iponeap, $riphex, $slt, $endhex\n"; + + // now we gmp_init + $gmpone = gmp_init($riphex); + $gmptwo = gmp_init($endhex); + + $array["start"] = $gmpone; + $array["end"] = $gmptwo; + + return $array; } function ip4ToComp($ip, $mask) { - + } class ip { - + static function isValid($ip, $mask = 0) { - + $ver = ipversion($ip); - + if($ver == 0) return 0; if($ver == 6) { @@ -72,11 +101,11 @@ class ip { return false; } else { $sns = $mask / 16; - + // now check that we have $sns number of subnets specified $pss = explode(":", $ip); $ns = count($pss); - + // we need to specify an error we can throw back at the user if($ns < $sns) { error_log("no 2, $ns, $sns, $ip"); @@ -89,27 +118,27 @@ class ip { return false; } } - + // we are still a valid ipv6 ip address/mask error_log("Valid"); return true; } } } - + if($ver == 4) { if($mask != 0) { return $ip; } } } - + static function truncateNetwork($ip, $mask) { $ver = ipversion($ip); - + if($ver == 0) return false; - + if($ver == 6) { if($mask != 0) { if($mask%16 != 0) { @@ -117,18 +146,18 @@ class ip { return false; } else { $sns = $mask / 16; - + // now check that we have $sns number of subnets specified $pss = explode(":", $ip); $ns = count($pss); - + // we need to specify an error we can throw back at the user if($ns < $sns) { error_log("no 2, $ns, $sns, $ip"); print_r($pss); return false; } - + $slt = ""; for($i = 0; $i < $sns; $i++) { if($i!=0) $slt .= ":"; @@ -138,25 +167,25 @@ class ip { } $slt .= "".$pss[$i]; } - + // we are still a valid ipv6 ip address/mask error_log("Valid"); return $slt; } } } - + if($ver == 4) { if($mask != 0) { return $ip; } } } - + function addSupernet($name, $sn, $mask, $desc) { global $db; - + if(ip::isValid($sn, $mask)) { $sn = ip::truncateNetwork($sn, $mask); $sql = "insert into supernet values (NULL, '$name', '$sn', '$mask', '$desc')"; @@ -165,33 +194,90 @@ class ip { } return false; } - + function addSubnet($name, $subnet, $mask, $desc, $super) { global $db; if(ip::isValid($subnet, $mask)) { - $sn = ip::truncateNetwork($sn, $mask); + $subnet = ip::truncateNetwork($subnet, $mask); // ("sn_id" INTEGER PRIMARY KEY AUTOINCREMENT,"snid_id" INTEGER,"sn_ip" TEXT,"sn_mask" TEXT,"sn_name" TEXT, "sn_desc" TEXT);'; - //if(!isSubnet($subnet, $mask, $super)) return "Is not a valid subnet"; - + if(!$this->isSubnet($subnet, $mask, $super)) return "Is not a valid subnet of the super range"; + if(!$this->isConflicting($subnet, $mask, $super)) return "Is conflicting with an existing allocation"; + $sql = "insert into subnet values (NULL, '$super', '$subnet', '$mask', '$name', '$desc')"; error_log("sql: $sql"); $db->dbobject->query($sql); return true; } } - + function isSubnet($subnet, $mask, $superid) { - return true; + global $db, $wwwConnector; + + $res = $db->dbobject->query("select * from supernet where sn_id=='$superid'"); + + foreach($res as $row) { + $sn = $row["sn_ip"]; + $sm = $row["sn_mask"]; + } + + if(ipversion($sn) == 6) { + // we ip6 to gmp the main subnet... + $aone = ip6ToGmp($sn, $sm); + + // we ip6togmp the sub sub... + $atwo = ip6ToGmp($subnet, $mask); + + // then we gmp compare the two... subnet[start] must be higher then (or equal) $supernet[start] and subnet[end] must be lower then or equal too $supernt[end]; + $cmp1 = gmp_cmp($aone["start"], $atwo["start"]); + $cmp2 = gmp_cmp($aone["end"], $atwo["end"]); + + error_log("cmp1, $cmp1, cmp2, $cmp2"); + // in order to be a subnet, $cmp1 should be 0 or negative, $cmp2 should be 0 or positive + if($cmp1 <= 0&&$cmp2 >= 0) return true; + return false; + } + if(ipversion($sn) == 4) { + // ERR, TODO + } + return true; } - + // this function returns true if it is NOT conflicting function isConflicting($subnet, $mask, $superid) { + global $db, $wwwConnector; + + if(ipversion($subnet) == 6) { + $res = $db->dbobject->query("select * from subnet where snid_id=='$superid'"); + + // we ip6togmp the sub sub... + $atwo = ip6ToGmp($subnet, $mask); + + foreach($res as $row) { + $sn = $row["sn_ip"]; + $sm = $row["sn_mask"]; + + // we ip6 to gmp the main subnet... + $aone = ip6ToGmp($sn, $sm); + + // in order to be not a collision, must be either $aone["end"] is lower then atwo["start"] or aone["start"] is higher then atwo["end"] + $cmp1 = gmp_cmp($aone["end"], $atwo["start"]); + $cmp2 = gmp_cmp($aone["start"], $atwo["end"]); + + error_log("conflighting cmp1, $cmp1, cmp2, $cmp2 ".gmp_strval($aone["end"])." - ".gmp_strval($aone["start"])." - ".gmp_strval($atwo["end"])." - ".gmp_strval($atwo["start"])." - "); + + if($cmp1 < 0) return true; + if($cmp2 > 0) return true; + + return false; + + } + } return true; } - + public $supers = ""; public $subs = ""; } diff --git a/lib/www.php b/lib/www.php index f38f5e8..3e23621 100644 --- a/lib/www.php +++ b/lib/www.php @@ -267,10 +267,11 @@ function www_ip_allocateSubRange() $desc = $_REQUEST["subdesc"]; $myip = new ip(); - if($myip->addSubnet($name, $subip, $mask, $desc, $superid)) { + $err = $myip->addSubnet($name, $subip, $mask, $desc, $superid); + if($err ===true) { header("Location: index.php?notice=range added"); } else { - header("Location: index.php?error=invalid ipaddress"); + header("Location: index.php?error=$err"); } } diff --git a/unittest/iptogmp.php b/unittest/iptogmp.php new file mode 100644 index 0000000..adf7a9f --- /dev/null +++ b/unittest/iptogmp.php @@ -0,0 +1,21 @@ + \ No newline at end of file -- 1.7.0.4