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