Skip to content

Commit 42f191b

Browse files
committed
Implemented support for UFW firewall (FS#1757 - New IPTables firewall script for IPv4 and IPv6)
1 parent ee0bc76 commit 42f191b

File tree

8 files changed

+231
-33
lines changed

8 files changed

+231
-33
lines changed

install/lib/installer_base.lib.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,15 @@ public function grant_master_database_rights($verbose = false) {
470470
if(!$this->dbmaster->query($query)) {
471471
$this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
472472
}
473+
474+
$query = "GRANT SELECT, UPDATE ON ".$value['db'].".`aps_instances` TO '".$value['user']."'@'".$host."' ";
475+
if ($verbose){
476+
echo $query ."\n";
477+
}
478+
if(!$this->dbmaster->query($query)) {
479+
$this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
480+
}
481+
473482
}
474483

475484
/*

install/tpl/server.ini.master

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ netmask=255.255.255.0
1111
gateway=192.168.0.1
1212
hostname=server1.domain.tld
1313
nameservers=192.168.0.1,192.168.0.2
14+
firewall=bastille
1415
loglevel=2
1516
backup_dir=/var/backup
1617
backup_mode=rootgz

interface/lib/classes/aps_crawler.inc.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private function checkRequirements()
6161
// Check if the cURL module is available
6262
if(!function_exists('curl_version')) throw new Exception('cURL is not available');
6363

64-
// Check if used folders are writable (chmod 777)
64+
// Check if used folders are writable
6565
if($this->interface_mode)
6666
{
6767
if(!is_writable($this->interface_pkg_dir))

interface/web/admin/form/server_config.tform.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@
9797
'width' => '15',
9898
'maxlength' => '255'
9999
),
100+
'firewall' => array(
101+
'datatype' => 'VARCHAR',
102+
'formtype' => 'SELECT',
103+
'default' => 'bastille',
104+
'value' => array('bastille' => 'bastille', 'ufw' => 'ufw'),
105+
'width' => '40',
106+
'maxlength' => '255'
107+
),
100108
'hostname' => array(
101109
'datatype' => 'VARCHAR',
102110
'formtype' => 'TEXT',

interface/web/admin/lib/lang/en_server_config.lng

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,5 @@ $wb["permissions_txt"] = 'Permissions';
162162
$wb["php_settings_txt"] = 'PHP Settings';
163163
$wb["apps_vhost_settings_txt"] = 'Apps Vhost Settings';
164164
$wb["awstats_settings_txt"] = 'AWStats Settings';
165+
$wb["firewall_txt"] = 'Firewall';
165166
?>

interface/web/admin/templates/server_config_server_edit.htm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ <h2><tmpl_var name="list_head_txt"></h2>
3333
<p class="formHint">{tmpl_var name='nameservers_hint_txt'}</p>
3434
</div>
3535
<div class="ctrlHolder">
36+
<label for="firewall">{tmpl_var name='firewall_txt'}</label>
37+
<select name="firewall" id="firewall" class="selectInput">
38+
{tmpl_var name='firewall'}
39+
</select>
40+
</div>
41+
<div class="ctrlHolder">
3642
<label for="loglevel">{tmpl_var name='loglevel_txt'}</label>
3743
<select name="loglevel" id="loglevel" class="selectInput">
3844
{tmpl_var name='loglevel'}

server/lib/classes/system.inc.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,16 @@ function mkdirpath($path, $mode = 0755, $user = '', $group = '') {
12711271
}
12721272

12731273
}
1274+
1275+
//* Check if a application is installed
1276+
function is_installed($appname) {
1277+
exec('which '.escapeshellcmd($appname).' 2> /dev/null',$out,$returncode);
1278+
if(isset($out[0]) && stristr($out[0],$appname) && $returncode == 0) {
1279+
return true;
1280+
} else {
1281+
return false;
1282+
}
1283+
}
12741284

12751285
}
12761286
?>

server/plugins-available/firewall_plugin.inc.php

Lines changed: 195 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030

3131
class firewall_plugin {
3232

33-
var $plugin_name = 'firewall_plugin';
34-
var $class_name = 'firewall_plugin';
33+
private $plugin_name = 'firewall_plugin';
34+
private $class_name = 'firewall_plugin';
3535

3636
//* This function is called during ispconfig installation to determine
3737
// if a symlink shall be created for this plugin.
38-
function onInstall() {
38+
public function onInstall() {
3939
global $conf;
4040

4141
if($conf['bastille']['installed'] = true && $conf['services']['firewall'] == true) {
@@ -51,7 +51,7 @@ function onInstall() {
5151
This function is called when the plugin is loaded
5252
*/
5353

54-
function onLoad() {
54+
public function onLoad() {
5555
global $app;
5656

5757
/*
@@ -62,51 +62,182 @@ function onLoad() {
6262
$app->plugins->registerEvent('firewall_insert',$this->plugin_name,'insert');
6363
$app->plugins->registerEvent('firewall_update',$this->plugin_name,'update');
6464
$app->plugins->registerEvent('firewall_delete',$this->plugin_name,'delete');
65+
}
66+
67+
68+
public function insert($event_name,$data) {
69+
global $app, $conf;
6570

71+
$this->update($event_name,$data);
6672

6773
}
6874

75+
public function update($event_name,$data) {
76+
global $app, $conf;
77+
78+
//* load the server configuration options
79+
$app->uses('getconf');
80+
$server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
81+
if($server_config['firewall'] == 'ufw') {
82+
$this->ufw_update($event_name,$data);
83+
} else {
84+
$this->bastille_update($event_name,$data);
85+
}
86+
87+
}
6988

70-
function insert($event_name,$data) {
89+
public function delete($event_name,$data) {
7190
global $app, $conf;
7291

73-
$this->update($event_name,$data);
92+
//* load the server configuration options
93+
$app->uses('getconf');
94+
$server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
95+
96+
if($server_config['firewall'] == 'ufw') {
97+
$this->ufw_delete($event_name,$data);
98+
} else {
99+
$this->bastille_delete($event_name,$data);
100+
}
74101

75102
}
76103

77-
function update($event_name,$data) {
104+
private function ufw_update($event_name,$data) {
78105
global $app, $conf;
79106

80-
$tcp_ports = '';
81-
$udp_ports = '';
107+
$app->uses('system');
82108

83-
$ports = explode(',',$data['new']['tcp_port']);
84-
if(is_array($ports)) {
85-
foreach($ports as $p) {
86-
if(strstr($p,':')) {
87-
$p_parts = explode(':',$p);
88-
$p_clean = intval($p_parts[0]).':'.intval($p_parts[1]);
89-
} else {
90-
$p_clean = intval($p);
91-
}
92-
$tcp_ports .= $p_clean . ' ';
109+
if(!$app->system->is_installed('ufw')) {
110+
$app->log('UFW Firewall is not installed',LOGLEVEL_WARN);
111+
return false;
112+
}
113+
114+
exec('ufw --version',$out);
115+
$parts = explode(' ',$out[0]);
116+
$ufwversion = $parts[1];
117+
unset($parts);
118+
unset($out);
119+
120+
if(version_compare ( $ufwversion , '0.30') < 0) {
121+
$app->log('The installed UFW Firewall version is too old. Minimum required version 0.30',LOGLEVEL_WARN);
122+
return false;
123+
}
124+
125+
//* Basic firewall setup when the firewall is added the first time
126+
if($event_name == 'firewall_insert') {
127+
exec('ufw --force disable');
128+
exec('ufw --force reset');
129+
exec('ufw default deny incoming');
130+
exec('ufw default allow outgoing');
131+
}
132+
133+
$tcp_ports_new = $this->clean_ports($data['new']['tcp_port'],',');
134+
$tcp_ports_old = $this->clean_ports($data['old']['tcp_port'],',');
135+
$udp_ports_new = $this->clean_ports($data['new']['udp_port'],',');
136+
$udp_ports_old = $this->clean_ports($data['old']['udp_port'],',');
137+
138+
$tcp_ports_new_array = explode(',',$tcp_ports_new);
139+
$tcp_ports_old_array = explode(',',$tcp_ports_old);
140+
$udp_ports_new_array = explode(',',$udp_ports_new);
141+
$udp_ports_old_array = explode(',',$udp_ports_old);
142+
143+
//* add tcp ports
144+
foreach($tcp_ports_new_array as $port) {
145+
if(!in_array($port,$tcp_ports_old_array) && $port > 0) {
146+
exec('ufw allow '.$port.'/tcp');
147+
$app->log('ufw allow '.$port.'/tcp',LOGLEVEL_DEBUG);
148+
sleep(1);
93149
}
94150
}
95-
$tcp_ports = trim($tcp_ports);
96151

97-
$ports = explode(',',$data['new']['udp_port']);
98-
if(is_array($ports)) {
99-
foreach($ports as $p) {
100-
if(strstr($p,':')) {
101-
$p_parts = explode(':',$p);
102-
$p_clean = intval($p_parts[0]).':'.intval($p_parts[1]);
103-
} else {
104-
$p_clean = intval($p);
105-
}
106-
$udp_ports .= $p_clean . ' ';
152+
//* remove tcp ports
153+
foreach($tcp_ports_old_array as $port) {
154+
if(!in_array($port,$tcp_ports_new_array) && $port > 0) {
155+
exec('ufw delete allow '.$port.'/tcp');
156+
$app->log('ufw delete allow '.$port.'/tcp',LOGLEVEL_DEBUG);
157+
sleep(1);
158+
}
159+
}
160+
161+
//* add udp ports
162+
foreach($udp_ports_new_array as $port) {
163+
if(!in_array($port,$udp_ports_old_array) && $port > 0) {
164+
exec('ufw allow '.$port.'/udp');
165+
$app->log('ufw allow '.$port.'/udp',LOGLEVEL_DEBUG);
166+
sleep(1);
167+
}
168+
}
169+
170+
//* remove udp ports
171+
foreach($udp_ports_old_array as $port) {
172+
if(!in_array($port,$udp_ports_new_array) && $port > 0) {
173+
exec('ufw delete allow '.$port.'/udp');
174+
$app->log('ufw delete allow '.$port.'/udp',LOGLEVEL_DEBUG);
175+
sleep(1);
176+
}
177+
}
178+
179+
/*
180+
if($tcp_ports_new != $tcp_ports_old) {
181+
exec('ufw allow to any proto tcp port '.$tcp_ports_new);
182+
$app->log('ufw allow to any proto tcp port '.$tcp_ports_new,LOGLEVEL_DEBUG);
183+
if($event_name == 'firewall_update') {
184+
exec('ufw delete allow to any proto tcp port '.$tcp_ports_old);
185+
$app->log('ufw delete allow to any proto tcp port '.$tcp_ports_old,LOGLEVEL_DEBUG);
186+
}
187+
}
188+
189+
if($udp_ports_new != $udp_ports_old) {
190+
exec('ufw allow to any proto udp port '.$udp_ports_new);
191+
$app->log('ufw allow to any proto udp port '.$udp_ports_new,LOGLEVEL_DEBUG);
192+
if($event_name == 'firewall_update') {
193+
exec('ufw delete allow to any proto udp port '.$udp_ports_old);
194+
$app->log('ufw delete allow to any proto udp port '.$udp_ports_old,LOGLEVEL_DEBUG);
195+
}
196+
}
197+
*/
198+
199+
if($data['new']['active'] == 'y') {
200+
if($data['new']['active'] == $data['old']['active']) {
201+
exec('ufw reload');
202+
$app->log('Reloading the firewall',LOGLEVEL_DEBUG);
203+
} else {
204+
//* Ensure that bastille firewall is stopped
205+
exec($conf['init_scripts'] . '/' . 'bastille-firewall stop');
206+
if(@is_file('/etc/debian_version')) exec('update-rc.d -f bastille-firewall remove');
207+
208+
//* Start ufw firewall
209+
exec('ufw --force enable');
210+
$app->log('Starting the firewall',LOGLEVEL_DEBUG);
107211
}
212+
} else {
213+
exec('ufw disable');
214+
$app->log('Stopping the firewall',LOGLEVEL_DEBUG);
215+
}
216+
}
217+
218+
private function ufw_delete($event_name,$data) {
219+
global $app, $conf;
220+
221+
$app->uses('system');
222+
223+
if(!$app->system->is_installed('ufw')) {
224+
$app->log('UFW Firewall is not installed',LOGLEVEL_DEBUG);
225+
return false;
108226
}
109-
$udp_ports = trim($udp_ports);
227+
228+
exec('ufw --force reset');
229+
exec('ufw disable');
230+
$app->log('Stopping the firewall',LOGLEVEL_DEBUG);
231+
232+
}
233+
234+
private function bastille_update($event_name,$data) {
235+
global $app, $conf;
236+
237+
$app->uses('system');
238+
239+
$tcp_ports = $this->clean_ports($data['new']['tcp_port'],' ');
240+
$udp_ports = $this->clean_ports($data['new']['udp_port'],' ');
110241

111242
$app->load('tpl');
112243
$tpl = new tpl();
@@ -120,6 +251,10 @@ function update($event_name,$data) {
120251
unset($tpl);
121252

122253
if($data['new']['active'] == 'y') {
254+
//* ensure that ufw firewall is disabled in case both firewalls are installed
255+
if($app->system->is_installed('ufw')) {
256+
exec('ufw disable');
257+
}
123258
exec($conf['init_scripts'] . '/' . 'bastille-firewall restart');
124259
if(@is_file('/etc/debian_version')) exec('update-rc.d bastille-firewall defaults');
125260
$app->log('Restarting the firewall',LOGLEVEL_DEBUG);
@@ -132,7 +267,7 @@ function update($event_name,$data) {
132267

133268
}
134269

135-
function delete($event_name,$data) {
270+
private function bastille_delete($event_name,$data) {
136271
global $app, $conf;
137272

138273
exec($conf['init_scripts'] . '/' . 'bastille-firewall stop');
@@ -142,6 +277,34 @@ function delete($event_name,$data) {
142277
}
143278

144279

280+
private function clean_ports($portlist,$spacer) {
281+
282+
$ports = explode(',',$portlist);
283+
$ports_out = '';
284+
285+
if(is_array($ports)) {
286+
foreach($ports as $p) {
287+
$p_clean = '';
288+
if(strstr($p,':')) {
289+
$p_parts = explode(':',$p);
290+
$tmp_lower = intval($p_parts[0]);
291+
$tmp_higher = intval($p_parts[1]);
292+
if($tmp_lower > 0 && $tmp_lower <= 65535 && $tmp_higher > 0 && $tmp_higher <= 65535 && $tmp_lower < $tmp_higher) {
293+
$p_clean = $tmp_lower.':'.$tmp_higher;
294+
}
295+
} else {
296+
$tmp = intval($p);
297+
if($tmp > 0 && $tmp <= 65535) {
298+
$p_clean = $tmp;
299+
}
300+
}
301+
if($p_clean != '') $ports_out .= $p_clean . $spacer;
302+
303+
}
304+
}
305+
return substr($ports_out,0,strlen($spacer)*-1);
306+
}
307+
145308

146309

147310
} // end class

0 commit comments

Comments
 (0)