ipclass refactored with class sorting and more efficient check method
[brisk.git] / web / Obj / ipclass.phh
1 <?php
2 /*
3  *  brisk - Obj/ipclass.phh
4  *
5  *  Copyright (C)      2015 Matteo Nastasi
6  *                          mailto: nastasi@alternativeoutput.it
7  *                                  matteo.nastasi@milug.org
8  *                          web: http://www.alternativeoutput.it
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * General Public License for more details. You should have received a
19  * copy of the GNU General Public License along with this program; if
20  * not, write to the Free Software Foundation, Inc, 59 Temple Place -
21  * Suite 330, Boston, MA 02111-1307, USA.
22  *
23  */
24
25 class IPClassItem {
26     var $addr;
27     var $mask;
28
29     function IPClassItem($ipset)
30     {
31         //split
32         $elem = split("/", $ipset, 2);
33         $addr = $elem[0];
34         if (!isset($elem[1])) {
35             fprintf(STDERR, "ORIG: %s\n", $ipset);
36         }
37         $mask = (int)$elem[1];
38
39         //convert mask
40
41         $this->mask = ((1<<($mask))-1) << (32 - $mask);
42         $this->addr = ip2long($addr) & $this->mask;
43
44         fprintf(STDERR, "New ipclass item: %x (%x)\n", $this->addr, $this->mask);
45     }
46
47     function match($ip)
48     {
49         // fprintf(STDERR, "IP: %x, ADDR: %x, MASK: %x -> (%d)\n",
50         //       $ip, $this->addr, $this->mask, ((ip2long($ip) & $this->mask) == $this->addr));
51         return (($ip & $this->mask) == $this->addr);
52     }
53
54     static function compare($a, $b)
55     {
56         if ($a->addr == $b->addr)
57             return (0);
58         return (($a->addr < $b->addr) ? -1 : 1);
59     }
60 }
61
62 class IPClass {
63     var $ipcl;
64
65     function IPClass()
66     {
67         $this->ipcl = NULL;
68     }
69
70     static function create($ip_in=NULL)
71     {
72         $thiz = new IPClass();
73
74         if ($ip_in != NULL)
75             $thiz->update($ip_in);
76
77         return ($thiz);
78     }
79
80
81     function update($ip_in)
82     {
83         $this->clean();
84
85         $this->ipcl = array();
86         for ($i = 0 ; $i < count($ip_in) ; $i++) {
87             $this->ipcl[$i] = new IPClassItem($ip_in[$i]);
88         }
89         usort($this->ipcl, array("IPClassItem", "compare"));
90     }
91
92     function clean()
93     {
94         if ($this->ipcl != NULL) {
95             $ct = count($this->ipcl);
96             for ($i = 0 ; $i < $ct ; $i++) {
97                 unset($this->ipcl[$i]);
98             }
99             $this->ipcl = NULL;
100         }
101     }
102
103     function check($ip_str)
104     {
105         $ip = ip2long($ip_str);
106
107         if (count($this->ipcl) == 0) {
108             return (FALSE);
109         }
110
111         if ($ip < $this->ipcl[0]->addr)
112             return (FALSE);
113
114         $imin = 0;
115         $imax = count($this->ipcl) - 1;
116
117         while ($imax >= $imin) {
118             $imid = intval($imin + (($imax - $imin) / 2));
119             // printf("X: %d M: %d N: %d | ", $arr[$imin], $arr[$imid], $arr[$imax]);
120             if ($this->ipcl[$imid]->addr == $ip) {
121                 break;
122             }
123             else if ($this->ipcl[$imid]->addr > $ip) {
124                 $imax = $imid - 1;
125             }
126             else {
127                 $imin = $imid + 1;
128             }
129         }
130         if ($this->ipcl[$imid]->addr > $ip) {
131             if ($imid > 0) {
132                 $imid--;
133             }
134             else {
135                 $imid = -1;
136             }
137         }
138
139         if ($imid > -1) {
140             if ($this->ipcl[$imid]->match($ip)) {
141                 fprintf(STDERR, "ban_list[%d] = %x (%x) MATCH\n", $imid,
142                         $this->ipcl[$imid]->addr, $this->ipcl[$imid]->mask);
143                 return(TRUE);
144             }
145         }
146         return (FALSE);
147     }
148 }
149 ?>