Iptables.php
[Pman.Admin] / Iptables.php
1 <?php
2 /***
3  * how this might work..
4  *
5  * a) login - if it's a new IP not seen that day
6  * --> touch /tmp/run_pman_admin_iptables
7  *
8  * cron every minute... ?? << could do some kind of IPC?!?
9  *
10  * if file exists -> run this code.
11  *
12  * This code finds all the IP's used in the last 24 hours.
13  * and opens the firew all for them.
14  *
15  *
16  *
17  *
18  *
19  
20  
21  *
22  *
23  */
24
25 require_once 'Pman.php';
26
27 class Pman_Admin_Iptables extends Pman {
28     
29     static $cli_desc = "Read ip addresses that have been used to log in, and add them to the iptables list..";
30     
31    
32     
33     function getAuth()
34     {
35         // add locking here..
36         
37         if (!$this->bootLoader->cli) {
38             die("cli only");
39         }
40     }
41     
42     function monitorFile()
43     {
44         $ev = DB_DataObject::Factory('Events');
45         $db = $ev->database();
46         
47         return '/tmp/run_pman_admin_iptables-'.$db;
48     }
49     
50     function get($opt = '')
51     {
52         
53         // monitor file
54         
55         $mf = $this->monitorFile();
56         
57         $fe = file_exists($mf);
58         if (empty($opt)) {
59             if (!$fe) {
60                 exit;
61             }
62         }
63         if ($fe) {
64             unlink($mf);
65         }
66         
67         // find IP's that have been used to log in.
68         // dump them to the iptables file.
69         // if it's different - apply it...
70         //DB_DataObject::debugLevel(1);
71         // need to get a list of users who have Admin.Iptables rights..
72         /*$gr = DB_DataObject::factory('group_rights');
73         $grps = $gr->groupsWithRights('Admin.Iptables', 'S');
74         
75         $gr = DB_DataObject::factory('groups');
76         $gr->get('name', 'Administrators');
77         $grps[] = $gr->id;
78         
79         $gm = DB_DataObject::factory('group_members');
80         $gm->whereAddIn('group_id', $grps, 'int');
81         $gm->selectAdd();
82         $gm->selectAdd('distinct(user_id) as user_id');
83         $peps = $gm->fetchAll('user_id');
84         
85         
86         */
87         
88         
89         $p = DB_DataObject::Factory('Person');
90         $p->autoJoin();
91         $p->whereAdd("join_company_id_id.comptype = 'OWNER'");
92         $p->selectAdd();
93         $p->selectAdd("{$p->tableName()}.id as  id");
94         
95         $peps = $p->fetchAll('id');
96         
97         switch( $e->getDatabaseConnection()->phptype) {
98             case 'mysql':
99                 $interval = "INTERVAL 1 DAY";
100                 break;
101             case 'pgsql':
102                 $interval = " INTERVAL '1 DAY'";
103                 break;
104             default:
105                 die("database NOT SUPPORTED?!");
106         }
107         
108         $e = DB_DataObject::factory('Events');
109         $e->action = 'LOGIN';
110         $e->selectAdd();
111         $e->selectAdd(" 
112             distinct(ipaddr) as ipaddr
113             max(event_when) + $interval as expires
114                      
115         ");
116         $e->person_table = DB_DataObject::factory('person')->tableName();
117         $e->whereAddIn('person_id', $peps, 'int');
118         $e->groupBy('ipaddr');
119         $e->whereAdd("event_when > NOW() - $interval");
120                 
121        
122         $ips = $e->fetchAll('ipaddr','expires');
123
124         //inet addr:202.67.151.28  Bcast:202.67.151.255  Mask:255.255.255.0
125         $ifconfig = System::which('ifconfig');
126         
127         if (!$ifconfig) {
128             $this->jerr("ifconfig could not be found.");
129         }
130
131         $if = $this->exec($ifconfig);
132         
133          
134         foreach(explode("\n", $if) as $l) {
135             //var_dump($l);
136             if (!preg_match('/inet addr/', $l)) {
137                 continue;
138             }
139             $match = array();
140             preg_match('/\s*inet addr:([0-9.]+)\s+/', $l, $match);
141             $ips[$match[1]] = ''; // no expiry...
142             
143         }
144         $this->ips = $ips;
145         $cache = ini_get('session.save-path') . '/pman_admin_iptables.cache';
146         
147         $this->updateTables();
148         
149          
150         exit;
151
152     }
153     function updateTables()
154     {
155        
156         require_once 'System.php';
157         
158         $iptables = System::which('iptables');
159         
160          if (!$iptables) {
161             $this->jerr("iptables could not be found.");
162         }
163         // this should have been set up already..
164         // in the base firewall code.
165        
166         
167         // -A INPUT -p udp -m udp --dport 5432 -j postgres
168         // -A INPUT -p tcp -m tcp --dport 5432 -j postgres
169         
170         
171         // /sbin/iptables -L postgres -v -n --line-numbers
172         
173         $res = $this->exec("{$iptables} -L postgres -v -n --line-numbers");   
174        
175        
176         $lastrulenum = 1;
177        
178         $remove = array();
179        
180         foreach(explode("\n", $res) as $i => $line) {
181             if ($i == 1) {
182                 $head = preg_split('/\s+/', $line);
183                 $head[10] = 'comments';
184             }
185             if ($i < 2) {
186                 continue;
187             }
188             
189             $ar = preg_split('/\s+/', $line);
190             if (count($ar) < 3) {
191                 continue;
192             }
193             $ar[10] = implode(' ',array_slice($ar, 10));
194             $row = array();
195             foreach($head as $k=>$v) {
196                 $row[$v] = $ar[$k];
197             }
198             print_r($row);
199             
200             if ($row['target'] != 'INPUT') {
201                 continue;
202             }
203             // got input rules now..
204             if (!empty($row['comment'])) {
205                 foreach((array)json_decode($row['comment']) as $k=>$v) {
206                     $row[$k] = $v;
207                 }
208             }
209             if (!empty($row['expires'])) {
210                 if (strtotime($row['expires']) < time()) {
211                     $remove[ $row['source'] ] = $row;
212                 }
213             }
214             $old[ $row['source'] ] = $row;
215             
216             $lastrulenum = $row['num'];
217             
218         }
219         exit;
220         //--comment
221         
222           
223          
224         foreach($this->ips as $ip=>$expires) {
225             $old = isset($cur[$ip]) ? $cur[$ip] : false;
226             if ($old) {
227                 if (strtotime($expires) <= strtotime($old['expires'])) {
228                     // expires time is the same..
229                     //?? make sure it's not flagged for removal..
230                     
231                     continue;
232                 }
233             }
234             
235             if ($old) {
236                 $this->exec("{$iptables} -R postgres {$old['num']} -s {$ip}/32 -j ACCEPT --comment ".
237                     escapeshellarg(json_encode(array('expires'=>$expires)))) ;
238                 
239                 if (isset($remove[$ip])) {
240                     unset($remove[$ip]);
241                 }
242                 continue;
243             }
244             
245             $this->exec("{$iptables} -I postgres {$lastrulenum} -s {$ip}/32 -j ACCEPT --comment ".
246                     escapeshellarg(json_encode(array('expires'=>$expires))));
247             
248                                    
249         }
250         
251         // remove rules that need deleting..
252         foreach($remove as $ip => $r) {
253             $this->exec("{$iptables} -d postgres {$r['num']} ");
254             
255         }
256         
257         
258   
259         
260     }
261     
262     
263     function createBase()
264     {
265         
266         $iptables = System::which('iptables');
267         if (!$iptables) {
268             $this->jerr("iptables could not be found.");
269         }
270         
271         
272         
273         $this->exec("{$iptables} -F postgres"); // flush old
274         $this->exec("{$iptables} -N postgres");  // create new..
275         
276         $this->exec($iptables. ' -A postgres -m limit --limit 2/min -j LOG '.
277                         '--log-prefix "IPTables-Dropped: " --log-level 4');
278         $this->exec("$iptables -A postgres -j DROP");  
279
280         
281         
282         
283         
284     }
285     
286     function exec($cmd)
287     {
288         echo "$cmd\n";
289         $ret =  `$cmd`;
290         echo $ret."\n";
291         return $ret;
292     }
293     
294 }