Marius Cramer
2014-08-13 42539643c396f9d8865dcf9a51b13dc869709d16
commit | author | age
7c99ef 1 <?php
T 2
3 /*
436ed8 4 Copyright (c) 2007, Till Brehm, projektfarm Gmbh
7c99ef 5 All rights reserved.
T 6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11       this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright notice,
13       this list of conditions and the following disclaimer in the documentation
14       and/or other materials provided with the distribution.
15     * Neither the name of ISPConfig nor the names of its contributors
16       may be used to endorse or promote products derived from this software without
17       specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 class firewall_plugin {
7fe908 32
42f191 33     private $plugin_name = 'firewall_plugin';
T 34     private $class_name  = 'firewall_plugin';
7fe908 35
392450 36     //* This function is called during ispconfig installation to determine
T 37     //  if a symlink shall be created for this plugin.
42f191 38     public function onInstall() {
392450 39         global $conf;
7fe908 40
80e3c9 41         if($conf['bastille']['installed'] = true && $conf['services']['firewall'] == true) {
T 42             return true;
43         } else {
44             return false;
45         }
7fe908 46
392450 47     }
7fe908 48
MC 49
7c99ef 50     /*
T 51          This function is called when the plugin is loaded
52     */
7fe908 53
42f191 54     public function onLoad() {
7c99ef 55         global $app;
7fe908 56
7c99ef 57         /*
T 58         Register for the events
59         */
7fe908 60
7c99ef 61         //* Mailboxes
7fe908 62         $app->plugins->registerEvent('firewall_insert', $this->plugin_name, 'insert');
MC 63         $app->plugins->registerEvent('firewall_update', $this->plugin_name, 'update');
64         $app->plugins->registerEvent('firewall_delete', $this->plugin_name, 'delete');
7c99ef 65     }
7fe908 66
MC 67
68     public function insert($event_name, $data) {
7c99ef 69         global $app, $conf;
7fe908 70
MC 71         $this->update($event_name, $data);
72
7c99ef 73     }
7fe908 74
MC 75     public function update($event_name, $data) {
7c99ef 76         global $app, $conf;
7fe908 77
42f191 78         //* load the server configuration options
5332dc 79         if(!$data['mirrored']) {
TB 80             $app->uses('getconf');
81             $server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
82             if($server_config['firewall'] == 'ufw') {
83                 $this->ufw_update($event_name, $data);
84             } else {
85                 $this->bastille_update($event_name, $data);
86             }
42f191 87         }
T 88     }
7fe908 89
MC 90     public function delete($event_name, $data) {
42f191 91         global $app, $conf;
7fe908 92
42f191 93         //* load the server configuration options
5332dc 94         if(!$data['mirrored']) {
TB 95             $app->uses('getconf');
96             $server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
7fe908 97
5332dc 98             if($server_config['firewall'] == 'ufw') {
TB 99                 $this->ufw_delete($event_name, $data);
100             } else {
101                 $this->bastille_delete($event_name, $data);
102             }
42f191 103         }
T 104     }
7fe908 105
MC 106     private function ufw_update($event_name, $data) {
42f191 107         global $app, $conf;
7fe908 108
42f191 109         $app->uses('system');
7fe908 110
42f191 111         if(!$app->system->is_installed('ufw')) {
7fe908 112             $app->log('UFW Firewall is not installed', LOGLEVEL_WARN);
42f191 113             return false;
T 114         }
7fe908 115
MC 116         exec('ufw --version', $out);
117         $parts = explode(' ', $out[0]);
42f191 118         $ufwversion = $parts[1];
T 119         unset($parts);
120         unset($out);
121
7fe908 122         if(version_compare( $ufwversion , '0.30') < 0) {
MC 123             $app->log('The installed UFW Firewall version is too old. Minimum required version 0.30', LOGLEVEL_WARN);
42f191 124             return false;
T 125         }
7fe908 126
42f191 127         //* Basic firewall setup when the firewall is added the first time
T 128         if($event_name == 'firewall_insert') {
129             exec('ufw --force disable');
130             exec('ufw --force reset');
131             exec('ufw default deny incoming');
132             exec('ufw default allow outgoing');
133         }
7fe908 134
MC 135         $tcp_ports_new = $this->clean_ports($data['new']['tcp_port'], ',');
136         $tcp_ports_old = $this->clean_ports($data['old']['tcp_port'], ',');
137         $udp_ports_new = $this->clean_ports($data['new']['udp_port'], ',');
138         $udp_ports_old = $this->clean_ports($data['old']['udp_port'], ',');
139
140         $tcp_ports_new_array = explode(',', $tcp_ports_new);
141         $tcp_ports_old_array = explode(',', $tcp_ports_old);
142         $udp_ports_new_array = explode(',', $udp_ports_new);
143         $udp_ports_old_array = explode(',', $udp_ports_old);
144
42f191 145         //* add tcp ports
T 146         foreach($tcp_ports_new_array as $port) {
7fe908 147             if(!in_array($port, $tcp_ports_old_array) && $port > 0) {
42f191 148                 exec('ufw allow '.$port.'/tcp');
7fe908 149                 $app->log('ufw allow '.$port.'/tcp', LOGLEVEL_DEBUG);
42f191 150                 sleep(1);
7c99ef 151             }
T 152         }
7fe908 153
42f191 154         //* remove tcp ports
T 155         foreach($tcp_ports_old_array as $port) {
7fe908 156             if(!in_array($port, $tcp_ports_new_array) && $port > 0) {
42f191 157                 exec('ufw delete allow '.$port.'/tcp');
7fe908 158                 $app->log('ufw delete allow '.$port.'/tcp', LOGLEVEL_DEBUG);
42f191 159                 sleep(1);
7c99ef 160             }
T 161         }
7fe908 162
42f191 163         //* add udp ports
T 164         foreach($udp_ports_new_array as $port) {
7fe908 165             if(!in_array($port, $udp_ports_old_array) && $port > 0) {
42f191 166                 exec('ufw allow '.$port.'/udp');
7fe908 167                 $app->log('ufw allow '.$port.'/udp', LOGLEVEL_DEBUG);
42f191 168                 sleep(1);
T 169             }
170         }
7fe908 171
42f191 172         //* remove udp ports
T 173         foreach($udp_ports_old_array as $port) {
7fe908 174             if(!in_array($port, $udp_ports_new_array) && $port > 0) {
42f191 175                 exec('ufw delete allow '.$port.'/udp');
7fe908 176                 $app->log('ufw delete allow '.$port.'/udp', LOGLEVEL_DEBUG);
42f191 177                 sleep(1);
T 178             }
179         }
7fe908 180
42f191 181         /*
T 182         if($tcp_ports_new != $tcp_ports_old) {
183             exec('ufw allow to any proto tcp port '.$tcp_ports_new);
184             $app->log('ufw allow to any proto tcp port '.$tcp_ports_new,LOGLEVEL_DEBUG);
185             if($event_name == 'firewall_update') {
186                 exec('ufw delete allow to any proto tcp port '.$tcp_ports_old);
187                 $app->log('ufw delete allow to any proto tcp port '.$tcp_ports_old,LOGLEVEL_DEBUG);
188             }
189         }
7fe908 190
42f191 191         if($udp_ports_new != $udp_ports_old) {
T 192             exec('ufw allow to any proto udp port '.$udp_ports_new);
193             $app->log('ufw allow to any proto udp port '.$udp_ports_new,LOGLEVEL_DEBUG);
194             if($event_name == 'firewall_update') {
195                 exec('ufw delete allow to any proto udp port '.$udp_ports_old);
196                 $app->log('ufw delete allow to any proto udp port '.$udp_ports_old,LOGLEVEL_DEBUG);
197             }
198         }
199         */
7fe908 200
42f191 201         if($data['new']['active'] == 'y') {
T 202             if($data['new']['active'] == $data['old']['active']) {
203                 exec('ufw reload');
7fe908 204                 $app->log('Reloading the firewall', LOGLEVEL_DEBUG);
42f191 205             } else {
T 206                 //* Ensure that bastille firewall is stopped
526b99 207                 exec($conf['init_scripts'] . '/' . 'bastille-firewall stop 2>/dev/null');
42f191 208                 if(@is_file('/etc/debian_version')) exec('update-rc.d -f bastille-firewall remove');
7fe908 209
42f191 210                 //* Start ufw firewall
T 211                 exec('ufw --force enable');
7fe908 212                 $app->log('Starting the firewall', LOGLEVEL_DEBUG);
42f191 213             }
T 214         } else {
215             exec('ufw disable');
7fe908 216             $app->log('Stopping the firewall', LOGLEVEL_DEBUG);
42f191 217         }
T 218     }
7fe908 219
MC 220     private function ufw_delete($event_name, $data) {
42f191 221         global $app, $conf;
7fe908 222
42f191 223         $app->uses('system');
7fe908 224
42f191 225         if(!$app->system->is_installed('ufw')) {
7fe908 226             $app->log('UFW Firewall is not installed', LOGLEVEL_DEBUG);
42f191 227             return false;
T 228         }
7fe908 229
42f191 230         exec('ufw --force reset');
T 231         exec('ufw disable');
7fe908 232         $app->log('Stopping the firewall', LOGLEVEL_DEBUG);
MC 233
42f191 234     }
7fe908 235
MC 236     private function bastille_update($event_name, $data) {
42f191 237         global $app, $conf;
7fe908 238
42f191 239         $app->uses('system');
7fe908 240
MC 241         $tcp_ports = $this->clean_ports($data['new']['tcp_port'], ' ');
242         $udp_ports = $this->clean_ports($data['new']['udp_port'], ' ');
243
334a9f 244         $app->load('tpl');
7c99ef 245         $tpl = new tpl();
663caf 246         $tpl->newTemplate('bastille-firewall.cfg.master');
7fe908 247
MC 248         $tpl->setVar('TCP_PUBLIC_SERVICES', $tcp_ports);
249         $tpl->setVar('UDP_PUBLIC_SERVICES', $udp_ports);
250
251         file_put_contents('/etc/Bastille/bastille-firewall.cfg', $tpl->grab());
252         $app->log('Writing firewall configuration /etc/Bastille/bastille-firewall.cfg', LOGLEVEL_DEBUG);
7c99ef 253         unset($tpl);
7fe908 254
663caf 255         if($data['new']['active'] == 'y') {
42f191 256             //* ensure that ufw firewall is disabled in case both firewalls are installed
T 257             if($app->system->is_installed('ufw')) {
258                 exec('ufw disable');
259             }
526b99 260             exec($conf['init_scripts'] . '/' . 'bastille-firewall restart 2>/dev/null');
7c99ef 261             if(@is_file('/etc/debian_version')) exec('update-rc.d bastille-firewall defaults');
006b57 262             if(@is_file('/sbin/insserv')) exec('insserv -d bastille-firewall');
7fe908 263             $app->log('Restarting the firewall', LOGLEVEL_DEBUG);
7c99ef 264         } else {
526b99 265             exec($conf['init_scripts'] . '/' . 'bastille-firewall stop 2>/dev/null');
a57e06 266             if(@is_file('/etc/debian_version')) exec('update-rc.d -f bastille-firewall remove');
006b57 267             if(@is_file('/sbin/insserv')) exec('insserv -r -f bastille-firewall');
7fe908 268             $app->log('Stopping the firewall', LOGLEVEL_DEBUG);
7c99ef 269         }
7fe908 270
MC 271
7c99ef 272     }
7fe908 273
MC 274     private function bastille_delete($event_name, $data) {
7c99ef 275         global $app, $conf;
7fe908 276
526b99 277         exec($conf['init_scripts'] . '/' . 'bastille-firewall stop 2>/dev/null');
a57e06 278         if(@is_file('/etc/debian_version')) exec('update-rc.d -f bastille-firewall remove');
006b57 279         if(@is_file('/sbin/insserv')) exec('insserv -r -f bastille-firewall');
7fe908 280         $app->log('Stopping the firewall', LOGLEVEL_DEBUG);
MC 281
7c99ef 282     }
7fe908 283
MC 284
285     private function clean_ports($portlist, $spacer) {
286
287         $ports = explode(',', $portlist);
42f191 288         $ports_out = '';
7fe908 289
42f191 290         if(is_array($ports)) {
T 291             foreach($ports as $p) {
292                 $p_clean = '';
7fe908 293                 if(strstr($p, ':')) {
MC 294                     $p_parts = explode(':', $p);
42f191 295                     $tmp_lower = intval($p_parts[0]);
T 296                     $tmp_higher = intval($p_parts[1]);
297                     if($tmp_lower > 0 && $tmp_lower <= 65535 && $tmp_higher > 0 && $tmp_higher <= 65535 && $tmp_lower < $tmp_higher) {
298                         $p_clean = $tmp_lower.':'.$tmp_higher;
299                     }
300                 } else {
301                     $tmp = intval($p);
302                     if($tmp > 0 && $tmp <= 65535) {
303                         $p_clean = $tmp;
304                     }
305                 }
306                 if($p_clean != '') $ports_out .= $p_clean . $spacer;
7fe908 307
42f191 308             }
T 309         }
7fe908 310         return substr($ports_out, 0, strlen($spacer)*-1);
42f191 311     }
7fe908 312
MC 313
7c99ef 314
T 315 } // end class
316
663caf 317 ?>