ug... i have no idea really...
[PHPIPManager.git] / lib / ip.php
1 <?php
2
3 function ipversion($ip)
4 {
5         $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);
6         $ipv6 = ereg("^[0-9a-fA-F:]+$", $ip);
7
8         error_log("ipversion, $ip, $ipv4, $ipv6");
9         if($ipv4 == 1) return 4;
10         if($ipv6 == 1) return 6;
11         return 0;
12 }
13
14 // this function tries to take a short representation of a ip6 address and converts it to a long one.
15 // this is not entirely going to work.. but we'll get back to this
16 function ip6ToLongStr($ip)
17 {
18         if(ipversion($ip)!=6) return false;
19
20         $pss = explode(":", $ip);
21         $ns = count($pss);
22
23         $nstr = "";
24         foreach($pss as $ele) {
25                 echo "ele: $ele\n";
26                 if($nstr != "") {
27                         $nstr .= ":";
28                         echo "add colon\n";
29                 }
30                 if(strlen($ele)<1) {
31                         // this is where we pad 8-count of 0000:
32                         echo "add pad count\n";
33                         $pds = 8-$ns+1;
34                         for($i=0; $i < $pds; $i++) {
35                                 $nstr .= "0000:";
36                         }
37                         $nstr = rtrim($nstr, ":");
38                 } else if(strlen($ele) < 4) {
39                         $nstr .= str_pad($ele, 4, "0", STR_PAD_LEFT);
40                 } else {
41                         $nstr .= $ele;
42                 }
43         }
44         return $nstr;
45 }
46
47 // this function converts an ip address to a comparable integer
48 // so we can bounds-check.
49 // it returns an array of [firstnum][lastnum]
50 // this is without a doubt one of the ugliest things i've ever done.
51 function ip6ToGmp($ip, $mask)
52 {
53         if(ipversion($ip)!=6) return false;
54
55         $ipone = ip::truncateNetwork($ip, $mask);
56         $iponeap = $ipone."::0";
57         $rip = ip6ToLongStr($iponeap);
58         
59         $riphex = "0x".str_replace(":", "", $rip);
60         
61         // f**king ugly
62         $sns = 8-($mask / 16);
63                 
64         $slt = $ipone;
65         for($i = 0; $i < $sns; $i++) {
66                 $slt .= ":FFFF";
67         }
68
69         $endhex = "0x".str_replace(":", "", ip6ToLongStr($slt));
70         
71         echo "$rip, $ipone, $iponeap, $riphex, $slt, $endhex\n";
72         
73         // now we gmp_init
74         $gmpone = gmp_init($riphex);
75         $gmptwo = gmp_init($endhex);
76         
77         $array["start"] = $gmpone;
78         $array["end"] = $gmptwo;
79         
80         return $array;
81 }
82
83 function ip4ToComp($ip, $mask)
84 {
85
86 }
87
88 class ip {
89
90         static function isValid($ip, $mask = 0)
91         {
92
93                 $ver = ipversion($ip);
94
95                 if($ver == 0) return 0;
96
97                 if($ver == 6) {
98                         if($mask != 0) {
99                                 if($mask%16 != 0) {
100                                         error_log("no");
101                                         return false;
102                                 } else {
103                                         $sns = $mask / 16;
104                                                 
105                                         // now check that we have $sns number of subnets specified
106                                         $pss = explode(":", $ip);
107                                         $ns = count($pss);
108                                                 
109                                         // we need to specify an error we can throw back at the user
110                                         if($ns < $sns) {
111                                                 error_log("no 2, $ns, $sns, $ip");
112                                                 print_r($pss);
113                                                 return false;
114                                         }
115                                         for($i = 0; $i < $sns; $i++) {
116                                                 if(strlen($pss[$i]) < 1) {
117                                                         error_log("no 3");
118                                                         return false;
119                                                 }
120                                         }
121                                                 
122                                         // we are still a valid ipv6 ip address/mask
123                                         error_log("Valid");
124                                         return true;
125                                 }
126                         }
127                 }
128
129                 if($ver == 4) {
130                         if($mask != 0) {
131                                 return $ip;
132                         }
133                 }
134         }
135
136         static function truncateNetwork($ip, $mask)
137         {
138                 $ver = ipversion($ip);
139
140                 if($ver == 0) return false;
141
142                 if($ver == 6) {
143                         if($mask != 0) {
144                                 if($mask%16 != 0) {
145                                         error_log("no");
146                                         return false;
147                                 } else {
148                                         $sns = $mask / 16;
149                                                 
150                                         // now check that we have $sns number of subnets specified
151                                         $pss = explode(":", $ip);
152                                         $ns = count($pss);
153                                                 
154                                         // we need to specify an error we can throw back at the user
155                                         if($ns < $sns) {
156                                                 error_log("no 2, $ns, $sns, $ip");
157                                                 print_r($pss);
158                                                 return false;
159                                         }
160                                                 
161                                         $slt = "";
162                                         for($i = 0; $i < $sns; $i++) {
163                                                 if($i!=0) $slt .= ":";
164                                                 if(strlen($pss[$i]) < 1) {
165                                                         error_log("no 3");
166                                                         return false;
167                                                 }
168                                                 $slt .= "".$pss[$i];
169                                         }
170                                                 
171                                         // we are still a valid ipv6 ip address/mask
172                                         error_log("Valid");
173                                         return $slt;
174                                 }
175                         }
176                 }
177
178                 if($ver == 4) {
179                         if($mask != 0) {
180                                 return $ip;
181                         }
182                 }
183         }
184
185         function addSupernet($name, $sn, $mask, $desc)
186         {
187                 global $db;
188
189                 if(ip::isValid($sn, $mask)) {
190                         $sn = ip::truncateNetwork($sn, $mask);
191                         $sql = "insert into supernet values (NULL, '$name', '$sn', '$mask', '$desc')";
192                         $db->dbobject->query($sql);
193                         return true;
194                 }
195                 return false;
196         }
197
198         function addSubnet($name, $subnet, $mask, $desc, $super)
199         {
200                 global $db;
201                 if(ip::isValid($subnet, $mask)) {
202                         $subnet = ip::truncateNetwork($subnet, $mask);
203                         // ("sn_id" INTEGER PRIMARY KEY AUTOINCREMENT,"snid_id" INTEGER,"sn_ip" TEXT,"sn_mask" TEXT,"sn_name" TEXT, "sn_desc" TEXT);';
204                         if(!$this->isSubnet($subnet, $mask, $super)) return "Is not a valid subnet of the super range";
205                         if(!$this->isConflicting($subnet, $mask, $super)) return "Is conflicting with an existing allocation";
206                                 
207                         $sql = "insert into subnet values (NULL, '$super', '$subnet', '$mask', '$name', '$desc')";
208                         error_log("sql: $sql");
209                         $db->dbobject->query($sql);
210                         return true;
211                 }
212         }
213
214         function isSubnet($subnet, $mask, $superid)
215         {
216                 global $db, $wwwConnector;
217
218                 $res = $db->dbobject->query("select * from supernet where sn_id=='$superid'");
219                 
220                 foreach($res as $row) {
221                         $sn = $row["sn_ip"];
222                         $sm = $row["sn_mask"];
223                 }
224                 
225                 if(ipversion($sn) == 6) {
226                         // we ip6 to gmp the main subnet...
227                         $aone = ip6ToGmp($sn, $sm);
228                         
229                         // we ip6togmp the sub sub...
230                         $atwo = ip6ToGmp($subnet, $mask);
231                         
232                         // 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];
233                         $cmp1 = gmp_cmp($aone["start"], $atwo["start"]);
234                         $cmp2 = gmp_cmp($aone["end"], $atwo["end"]);
235                         
236                         error_log("cmp1, $cmp1, cmp2, $cmp2");
237                         // in order to be a subnet, $cmp1 should be 0 or negative, $cmp2 should be 0 or positive
238                         if($cmp1 <= 0&&$cmp2 >= 0) return true;
239                         return false;
240                 }
241                 if(ipversion($sn) == 4) {
242                         // ERR, TODO
243                 }
244                 return true;            
245         }
246
247         // this function returns true if it is NOT conflicting
248         function isConflicting($subnet, $mask, $superid)
249         {
250                 global $db, $wwwConnector;
251
252                 if(ipversion($subnet) == 6) {
253                         $res = $db->dbobject->query("select * from subnet where snid_id=='$superid'");
254                                 
255                         // we ip6togmp the sub sub...
256                         $atwo = ip6ToGmp($subnet, $mask);
257
258                         foreach($res as $row) {
259                                 $sn = $row["sn_ip"];
260                                 $sm = $row["sn_mask"];
261                                 
262                                 // we ip6 to gmp the main subnet...
263                                 $aone = ip6ToGmp($sn, $sm);
264                                 
265                                 // 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"] 
266                                 $cmp1 = gmp_cmp($aone["end"], $atwo["start"]);
267                                 $cmp2 = gmp_cmp($aone["start"], $atwo["end"]);
268                                 
269                                 error_log("conflighting cmp1, $cmp1, cmp2, $cmp2 ".gmp_strval($aone["end"])." - ".gmp_strval($aone["start"])." - ".gmp_strval($atwo["end"])." - ".gmp_strval($atwo["start"])." - ");
270                                 
271                                 if($cmp1 < 0) return true;
272                                 if($cmp2 > 0) return true;
273                                 
274                                 return false;
275                                 
276                         }
277                 }
278                 return true;
279         }
280
281         public $supers = "";
282         public $subs = "";
283 }
284 ?>