From 525024a205716a418a877ad012db34fc78f6169a Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Sun, 4 Jan 2015 21:02:11 +0100 Subject: added manawall --- Makefile.PL | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.PL b/Makefile.PL index 834e6e03..3bd403b3 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -72,6 +72,7 @@ WriteMakefile( scripts/manaproxy scripts/manaservice scripts/manauser + scripts/manawall modules/contribfinder.py modules/rpmdragora/dragora-urpm-addmedia modules/rpmdragora/dragora-urpm-sources.pl -- cgit v1.2.1 From 1ee8f273ca2ae5723ea765fce2ff2ac488789dfc Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Sun, 4 Jan 2015 21:02:52 +0100 Subject: added launch script for manawall --- scripts/manawall | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 scripts/manawall diff --git a/scripts/manawall b/scripts/manawall new file mode 100755 index 00000000..30b64803 --- /dev/null +++ b/scripts/manawall @@ -0,0 +1,36 @@ +#!/usr/bin/perl +# Copyright 2013 Matteo Pasotti +# +# This file is part of hostmanager thus adminpanel +# +# hostmanager is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# hostmanager is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . +use Modern::Perl '2011'; +use autodie; +use AdminPanel::Module::Firewall; + +use yui; + +my $wm_icon = "/usr/share/mcc/themes/default/firewall-mdk.png"; +my $wm_name = "Manage firewall rules"; + +yui::YUI::app()->setApplicationTitle($wm_name); +yui::YUI::app()->setApplicationIcon($wm_icon); + +my $hostMan = AdminPanel::Module::Firewall->new({ + icon => $wm_icon, + name => $wm_name + }); +$hostMan->start(); + +1; -- cgit v1.2.1 From bc332b7a18480a7c8db34ba45bd9ecfc257eaf75 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Sun, 4 Jan 2015 21:04:20 +0100 Subject: added basic modules for firewall configuration (still not working) --- lib/AdminPanel/Module/Firewall.pm | 461 ++++++++++++++++++++++++++++++++++++++ lib/AdminPanel/Shared/Firewall.pm | 37 +++ 2 files changed, 498 insertions(+) create mode 100644 lib/AdminPanel/Module/Firewall.pm create mode 100644 lib/AdminPanel/Shared/Firewall.pm diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm new file mode 100644 index 00000000..94613c05 --- /dev/null +++ b/lib/AdminPanel/Module/Firewall.pm @@ -0,0 +1,461 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2015 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Module::Firewall; + +use Modern::Perl '2011'; +use autodie; +use Moose; +use utf8; + +use yui; +use AdminPanel::Shared qw(trim); +use AdminPanel::Shared::GUI; +use AdminPanel::Shared::Firewall; + +extends qw( AdminPanel::Module ); + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/firewall-mdk.png", +); + +has '+name' => ( + default => "Firewall Manager", +); + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +has 'dialog' => ( + is => 'rw', + init_arg => undef +); + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize', + required => 1, +); + +has 'all_servers' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', +); + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(AdminPanel::Shared::Locales->new(domain_name => 'drakx-net') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui(AdminPanel::Shared::GUI->new() ); +} + +sub _initAllServers { + my $self = shift(); + my @all_servers = ( + { + name => $self->loc->N("Web Server"), + pkg => 'apache apache-mod_perl boa lighttpd thttpd', + ports => '80/tcp 443/tcp', + }, + { + name => $self->loc->N("Domain Name Server"), + pkg => 'bind dnsmasq mydsn', + ports => '53/tcp 53/udp', + }, + { + name => $self->loc->N("SSH server"), + pkg => 'openssh-server', + ports => '22/tcp', + }, + { + name => $self->loc->N("FTP server"), + pkg => 'ftp-server-krb5 wu-ftpd proftpd pure-ftpd', + ports => '20/tcp 21/tcp', + }, + { + name => $self->loc->N("DHCP Server"), + pkg => 'dhcp-server udhcpd', + ports => '67/udp 68/udp', + hide => 1, + }, + { + name => $self->loc->N("Mail Server"), + pkg => 'sendmail postfix qmail exim', + ports => '25/tcp 465/tcp 587/tcp', + }, + { + name => $self->loc->N("POP and IMAP Server"), + pkg => 'imap courier-imap-pop', + ports => '109/tcp 110/tcp 143/tcp 993/tcp 995/tcp', + }, + { + name => $self->loc->N("Telnet server"), + pkg => 'telnet-server-krb5', + ports => '23/tcp', + hide => 1, + }, + { + name => $self->loc->N("NFS Server"), + pkg => 'nfs-utils nfs-utils-clients', + ports => '111/tcp 111/udp 2049/tcp 2049/udp ' . network::nfs::list_nfs_ports(), + hide => 1, + prepare => sub { network::nfs::write_nfs_ports(network::nfs::read_nfs_ports()) }, + restart => 'nfs-common nfs-server', + }, + { + name => $self->loc->N("Windows Files Sharing (SMB)"), + pkg => 'samba-server', + ports => '137/tcp 137/udp 138/tcp 138/udp 139/tcp 139/udp 445/tcp 445/udp 1024:1100/tcp 1024:1100/udp', + hide => 1, + }, + { + name => $self->loc->N("Bacula backup"), + pkg => 'bacula-fd bacula-sd bacula-dir-common', + ports => '9101:9103/tcp', + hide => 1, + }, + { + name => $self->loc->N("Syslog network logging"), + pkg => 'rsyslog syslog-ng', + ports => '514/udp', + hide => 1, + }, + { + name => $self->loc->N("CUPS server"), + pkg => 'cups', + ports => '631/tcp 631/udp', + hide => 1, + }, + { + name => $self->loc->N("MySQL server"), + pkg => 'mysql', + ports => '3306/tcp 3306/udp', + hide => 1, + }, + { + name => $self->loc->N("PostgreSQL server"), + pkg => 'postgresql8.2 postgresql8.3', + ports => '5432/tcp 5432/udp', + hide => 1, + }, + { + name => $self->loc->N("Echo request (ping)"), + ports => '8/icmp', + force_default_selection => 0, + }, + { + name => $self->loc->N("Network services autodiscovery (zeroconf and slp)"), + ports => '5353/udp 427/udp', + pkg => 'avahi cups openslp', + }, + { + name => $self->loc->N("BitTorrent"), + ports => '6881:6999/tcp 6881:6999/udp', + hide => 1, + pkg => 'bittorrent deluge ktorrent transmission vuze rtorrent ctorrent', + }, + { + name => $self->loc->N("Windows Mobile device synchronization"), + pkg => 'synce-hal', + ports => '990/tcp 999/tcp 5678/tcp 5679/udp 26675/tcp', + hide => 1, + }, + ); + return \@all_servers; +} + +#============================================================= + +=head2 port2server + +=head3 INPUT + + $self: this object + + $ports: port object + +=head3 DESCRIPTION + + This method retrieves the server from a given port + +=cut + +#============================================================= + +sub port2server { + my $self = shift(); + my ($port) = @_; + find { + any { $port eq $_ } split(' ', $_->{ports}); + } $self->all_servers(); +} + +#============================================================= + +=head2 from_ports + +=head3 INPUT + + $self: this object + + $ports: ports object + +=head3 DESCRIPTION + + This method does... + +=cut + +#============================================================= + +sub from_ports { + my $self = shift(); + my ($ports) = @_; + + my @l; + my @unlisted; + foreach (split ' ', $ports) { + if (my $s = $self->port2server($_)) { + push @l, $s; + } else { + push @unlisted, $_; + } + } + [ uniq(@l) ], join(' ', @unlisted); +} + +#============================================================= + +=head2 get_conf + +=head3 INPUT + + $self: this object + + $disabled: boolean + + $o_ports: object representing ports + +=head3 DESCRIPTION + + This method retrieves the configuration + +=cut + +#============================================================= + +sub get_conf { + my $self = shift(); + my ($disabled, $o_ports) = @_; + my $possible_servers = undef; + + if ($o_ports) { + return ($disabled, from_ports($o_ports)); + } elsif (my $shorewall = network::shorewall::read()) { + # WARNING: this condition fails (the method fails) + # if manawall runs as unprivileged user + # cause it can't read the interfaces file + return ($shorewall->{disabled}, $self->from_ports($shorewall->{ports}), $shorewall->{log_net_drop}); + } else { + $self->sh_gui->ask_OkCancel({title => $self->loc->N("Firewall configuration"), text => $self->loc->N("drakfirewall configurator + +This configures a personal firewall for this Mageia machine."), richtext => 1}) or return; + + $self->sh_gui->ask_OkCancel({title => $self->loc->N("Firewall configuration"), text => $self->loc->N("drakfirewall configurator + +Make sure you have configured your Network/Internet access with +drakconnect before going any further."), richtext => 1}) or return; + + return($disabled, $possible_servers, ''); + } +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= + +sub start { + my $self = shift; + + $self->all_servers($self->_initAllServers()); + + my ($disabled, $servers, $unlisted, $log_net_drop) = $self->get_conf(undef) or return; + + $self->_manageFirewallDialog(); +}; + +#============================================================= + +sub _manageFirewallDialog { + my $self = shift; + + ## TODO fix for adminpanel + my $appTitle = yui::YUI::app()->applicationTitle(); + my $appIcon = yui::YUI::app()->applicationIcon(); + ## set new title to get it in dialog + my $newTitle = $self->loc->N("Manage firewall rules"); + yui::YUI::app()->setApplicationTitle($newTitle); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + + $self->dialog($factory->createMainDialog()); + my $layout = $factory->createVBox($self->dialog); + + my $hbox_header = $factory->createHBox($layout); + my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); + my $headRight = $factory->createHBox($factory->createRight($hbox_header)); + + my $logoImage = $factory->createImage($headLeft, $appIcon); + my $labelAppDescription = $factory->createLabel($headRight,$newTitle); + $logoImage->setWeight($yui::YD_HORIZ,0); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + + my $leftContent = $factory->createLeft($hbox_content); + $leftContent->setWeight($yui::YD_HORIZ,45); + + for my $v(@{$self->all_servers()}) + { + #use Data::Dumper; + #print Dumper($v); + } + + my $rightContent = $factory->createRight($hbox_content); + $rightContent->setWeight($yui::YD_HORIZ,10); + my $topContent = $factory->createTop($rightContent); + my $vbox_commands = $factory->createVBox($topContent); + my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Add")); + my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Edit")); + my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Remove")); + my $hnButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Hostname")); + $addButton->setWeight($yui::YD_HORIZ,1); + $edtButton->setWeight($yui::YD_HORIZ,1); + $remButton->setWeight($yui::YD_HORIZ,1); + $hnButton->setWeight($yui::YD_HORIZ,1); + + my $hbox_foot = $factory->createHBox($layout); + my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); + my $vbox_foot_right = $factory->createVBox($factory->createRight($hbox_foot)); + my $aboutButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("OK")); + + # main loop + while(1) { + my $event = $self->dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { +### Buttons and widgets ### + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $addButton) { + $self->_addHostDialog(); + $self->setupTable(); + } + elsif ($widget == $edtButton) { + my $tblItem = yui::toYTableItem($self->table->selectedItem()); + if($tblItem->cellCount() >= 3){ + $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),$tblItem->cell(2)->label()); + }else{ + $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),""); + } + $self->setupTable(); + } + elsif ($widget == $remButton) { + # implement deletion dialog + if($self->sh_gui->ask_YesOrNo({title => $self->loc->N("Confirmation"), text => $self->loc->N("Are you sure to drop this host?")}) == 1){ + my $tblItem = yui::toYTableItem($self->table->selectedItem()); + # drop the host using the ip + $self->cfgHosts->_dropHost($tblItem->cell(0)->label()); + # write changes + $self->cfgHosts->_writeHosts(); + $self->setupTable(); + } + }elsif ($widget == $hnButton) { + $self->_changeHostNameDialog("Change the HostName FQDN"); + $self->setupTable(); + }elsif ($widget == $aboutButton) { + $self->sh_gui->AboutDialog({ + name => $appTitle, + version => $VERSION, + credits => "Copyright (c) 2013-2014 by Matteo Pasotti", + license => "GPLv2", + description => $self->loc->N("Graphical manager for hosts definitions"), + authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" + } + ); + }elsif ($widget == $okButton) { + # write changes + $self->cfgHosts->_writeHosts(); + last; + } + } + } + + $self->dialog->destroy() ; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/AdminPanel/Shared/Firewall.pm b/lib/AdminPanel/Shared/Firewall.pm new file mode 100644 index 00000000..2638ff87 --- /dev/null +++ b/lib/AdminPanel/Shared/Firewall.pm @@ -0,0 +1,37 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2014 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +package AdminPanel::Shared::Firewall; + +use Moose; +use diagnostics; +use utf8; + +use lib qw(/usr/lib/libDrakX); +# WARNING: using common +use common; +use network::nfs; +use network::network; +use network::shorewall; + +sub _initialize { + my $self = shift(); +} + +1; -- cgit v1.2.1 From 989b2c795ea330c6776c155be965de2e45cddb95 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Mon, 5 Jan 2015 00:54:02 +0100 Subject: - defined net attribute - fixed port2server - completed basic (working) implementation for choose_allowed_services - defined ask_AllowedServices method --- lib/AdminPanel/Module/Firewall.pm | 204 +++++++++++++++++++++++++------------- 1 file changed, 134 insertions(+), 70 deletions(-) diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm index 94613c05..9226667c 100644 --- a/lib/AdminPanel/Module/Firewall.pm +++ b/lib/AdminPanel/Module/Firewall.pm @@ -30,6 +30,11 @@ use AdminPanel::Shared qw(trim); use AdminPanel::Shared::GUI; use AdminPanel::Shared::Firewall; +use List::Util qw(any); +use List::MoreUtils qw(uniq); + +use MDK::Common::Func qw(if_); + extends qw( AdminPanel::Module ); has '+icon' => ( @@ -72,6 +77,13 @@ has 'all_servers' => ( isa => 'ArrayRef', ); +has 'net' => ( + is => 'rw', + init_arg => undef, + isa => 'HashRef', + builder => '_initNet', +); + sub _localeInitialize { my $self = shift(); @@ -201,6 +213,13 @@ sub _initAllServers { return \@all_servers; } +sub _initNet { + my $self = shift(); + my $net = {}; + network::network::read_net_conf($net); + return $net; +} + #============================================================= =head2 port2server @@ -222,9 +241,14 @@ sub _initAllServers { sub port2server { my $self = shift(); my ($port) = @_; - find { - any { $port eq $_ } split(' ', $_->{ports}); - } $self->all_servers(); + for my $service(@{$self->all_servers()}) + { + if(any { $port eq $_ } split(' ', $service->{ports})) + { + return $service; + } + } + return 0; } #============================================================= @@ -294,14 +318,20 @@ sub get_conf { # cause it can't read the interfaces file return ($shorewall->{disabled}, $self->from_ports($shorewall->{ports}), $shorewall->{log_net_drop}); } else { - $self->sh_gui->ask_OkCancel({title => $self->loc->N("Firewall configuration"), text => $self->loc->N("drakfirewall configurator - -This configures a personal firewall for this Mageia machine."), richtext => 1}) or return; - - $self->sh_gui->ask_OkCancel({title => $self->loc->N("Firewall configuration"), text => $self->loc->N("drakfirewall configurator - + $self->sh_gui->ask_OkCancel({ + title => $self->loc->N("Firewall configuration"), + text => $self->loc->N("drakfirewall configurator + This configures a personal firewall for this Mageia machine."), + richtext => 1 + }) or return; + + $self->sh_gui->ask_OkCancel({ + title => $self->loc->N("Firewall configuration"), + text => $self->loc->N("drakfirewall configurator Make sure you have configured your Network/Internet access with -drakconnect before going any further."), richtext => 1}) or return; +drakconnect before going any further."), + richtext => 1 + }) or return; return($disabled, $possible_servers, ''); } @@ -309,6 +339,73 @@ drakconnect before going any further."), richtext => 1}) or return; #============================================================= +=head2 choose_allowed_services + +=head3 INPUT + + $self: this object + + $disabled: boolean + + $servers: array of hashes representing servers + + $unlisted: array of hashes with the port not listed (???) + + $log_net_drop: network::shorewall log_net_drop attribute + +=head3 DESCRIPTION + + This method shows the main dialog to let users choose the allowed services + +=cut + +#============================================================= + +sub choose_allowed_services { + my ($self, $disabled, $servers, $unlisted, $log_net_drop) = @_; + + $_->{on} = 0 foreach @{$self->all_servers()}; + $_->{on} = 1 foreach @$servers; + my @l = grep { $_->{on} || !$_->{hide} } @{$self->all_servers()}; + + my $dialog_data = { + title => $self->loc->N("Firewall"), + icon => $network::shorewall::firewall_icon, + # if_(!$::isEmbedded, banner_title => $self->loc->N("Firewall")), + banner_title => $self->loc->N("Firewall"), + advanced_messages => $self->loc->N("You can enter miscellaneous ports. +Valid examples are: 139/tcp 139/udp 600:610/tcp 600:610/udp. +Have a look at /etc/services for information."), +# callbacks => { +# complete => sub { +# if (my $invalid_port = check_ports_syntax($unlisted)) { +# $in->ask_warn('', $self->loc->N("Invalid port given: %s. +# The proper format is \"port/tcp\" or \"port/udp\", +# where port is between 1 and 65535. +# +# You can also give a range of ports (eg: 24300:24350/udp)", $invalid_port)); +# return 1; +# } +# }, +# } + }; + + my $items = [ + { label => $self->loc->N("Which services would you like to allow the Internet to connect to?"), title => 1 }, + if_($self->net()->{PROFILE} && network::network::netprofile_count() > 0, { label => $self->loc->N("Those settings will be saved for the network profile %s", $self->net()->{PROFILE}) }), + { text => $self->loc->N("Everything (no firewall)"), val => \$disabled, type => 'bool' }, + (map { { text => $_->{name}, val => \$_->{on}, type => 'bool', disabled => sub { $disabled } } } @l), + { label => $self->loc->N("Other ports"), val => \$unlisted, advanced => 1, disabled => sub { $disabled } }, + { text => $self->loc->N("Log firewall messages in system logs"), val => \$log_net_drop, type => 'bool', advanced => 1, disabled => sub { $disabled } }, + ]; + + $self->ask_AllowedServices($dialog_data, $items) or return; + + return ($disabled, [ grep { $_->{on} } @l ], $unlisted, $log_net_drop); +} + +#============================================================= + =head2 start =head3 INPUT @@ -329,27 +426,29 @@ sub start { $self->all_servers($self->_initAllServers()); + + my ($disabled, $servers, $unlisted, $log_net_drop) = $self->get_conf(undef) or return; + ($disabled, $servers, $unlisted, $log_net_drop) = $self->choose_allowed_services($disabled, $servers, $unlisted, $log_net_drop) or return; - $self->_manageFirewallDialog(); }; #============================================================= -sub _manageFirewallDialog { +sub ask_AllowedServices { my $self = shift; - ## TODO fix for adminpanel - my $appTitle = yui::YUI::app()->applicationTitle(); - my $appIcon = yui::YUI::app()->applicationIcon(); + my ($dlg_data, + $items) = @_; + + my $old_title = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog - my $newTitle = $self->loc->N("Manage firewall rules"); - yui::YUI::app()->setApplicationTitle($newTitle); + yui::YUI::app()->setApplicationTitle($dlg_data->{title}); my $factory = yui::YUI::widgetFactory; my $optional = yui::YUI::optionalWidgetFactory; - $self->dialog($factory->createMainDialog()); my $layout = $factory->createVBox($self->dialog); @@ -357,34 +456,26 @@ sub _manageFirewallDialog { my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); my $headRight = $factory->createHBox($factory->createRight($hbox_header)); - my $logoImage = $factory->createImage($headLeft, $appIcon); - my $labelAppDescription = $factory->createLabel($headRight,$newTitle); + my $logoImage = $factory->createImage($headLeft, $dlg_data->{icon}); + my $labelAppDescription = $factory->createLabel($headRight,$dlg_data->{title}); $logoImage->setWeight($yui::YD_HORIZ,0); $labelAppDescription->setWeight($yui::YD_HORIZ,3); my $hbox_content = $factory->createHBox($layout); - my $leftContent = $factory->createLeft($hbox_content); - $leftContent->setWeight($yui::YD_HORIZ,45); + my $widgetContainer = $factory->createVBox($hbox_content); - for my $v(@{$self->all_servers()}) + foreach my $item(@{$items}) { - #use Data::Dumper; - #print Dumper($v); + if(defined($item->{label})) + { + $factory->createLabel($widgetContainer, $item->{label}); + } + elsif(defined($item->{text})) + { + $factory->createLabel($widgetContainer, $item->{text} . " - ". $item->{val} . " - " . $item->{type}); + } } - - my $rightContent = $factory->createRight($hbox_content); - $rightContent->setWeight($yui::YD_HORIZ,10); - my $topContent = $factory->createTop($rightContent); - my $vbox_commands = $factory->createVBox($topContent); - my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Add")); - my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Edit")); - my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Remove")); - my $hnButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("Hostname")); - $addButton->setWeight($yui::YD_HORIZ,1); - $edtButton->setWeight($yui::YD_HORIZ,1); - $remButton->setWeight($yui::YD_HORIZ,1); - $hnButton->setWeight($yui::YD_HORIZ,1); my $hbox_foot = $factory->createHBox($layout); my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); @@ -407,46 +498,19 @@ sub _manageFirewallDialog { my $widget = $event->widget(); if ($widget == $cancelButton) { last; - } - elsif ($widget == $addButton) { - $self->_addHostDialog(); - $self->setupTable(); - } - elsif ($widget == $edtButton) { - my $tblItem = yui::toYTableItem($self->table->selectedItem()); - if($tblItem->cellCount() >= 3){ - $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),$tblItem->cell(2)->label()); - }else{ - $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),""); - } - $self->setupTable(); - } - elsif ($widget == $remButton) { - # implement deletion dialog - if($self->sh_gui->ask_YesOrNo({title => $self->loc->N("Confirmation"), text => $self->loc->N("Are you sure to drop this host?")}) == 1){ - my $tblItem = yui::toYTableItem($self->table->selectedItem()); - # drop the host using the ip - $self->cfgHosts->_dropHost($tblItem->cell(0)->label()); - # write changes - $self->cfgHosts->_writeHosts(); - $self->setupTable(); - } - }elsif ($widget == $hnButton) { - $self->_changeHostNameDialog("Change the HostName FQDN"); - $self->setupTable(); }elsif ($widget == $aboutButton) { $self->sh_gui->AboutDialog({ - name => $appTitle, + name => $dlg_data->{title}, version => $VERSION, - credits => "Copyright (c) 2013-2014 by Matteo Pasotti", + credits => "Copyright (c) 2013-2015 by Matteo Pasotti", license => "GPLv2", - description => $self->loc->N("Graphical manager for hosts definitions"), + description => $self->loc->N("Graphical manager for firewall rules"), authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" } ); }elsif ($widget == $okButton) { # write changes - $self->cfgHosts->_writeHosts(); + return last; } } @@ -455,7 +519,7 @@ sub _manageFirewallDialog { $self->dialog->destroy() ; #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); + yui::YUI::app()->setApplicationTitle($old_title); } 1; -- cgit v1.2.1 From 3245ba86636be5d4d63ca44be85ecac03d6a630e Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Mon, 5 Jan 2015 20:44:53 +0100 Subject: - use Moose::Autobox - use various MDK::Common::(Func,System,Various) - aboutDialog shared between two dialogs - each all_servers item now provides an id attribute - ported sub to_ports, choose_watched_services for interactive firewall configuration (working) - added ask_WatchedServices - choose_allowed_services: base functionality complete - ported set_ports (still work in progress to drop dep from interactive) --- lib/AdminPanel/Module/Firewall.pm | 445 ++++++++++++++++++++++++++++++++++---- 1 file changed, 398 insertions(+), 47 deletions(-) diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm index 9226667c..d9c8ff54 100644 --- a/lib/AdminPanel/Module/Firewall.pm +++ b/lib/AdminPanel/Module/Firewall.pm @@ -23,6 +23,7 @@ package AdminPanel::Module::Firewall; use Modern::Perl '2011'; use autodie; use Moose; +use Moose::Autobox; use utf8; use yui; @@ -33,7 +34,9 @@ use AdminPanel::Shared::Firewall; use List::Util qw(any); use List::MoreUtils qw(uniq); -use MDK::Common::Func qw(if_); +use MDK::Common::Func qw(if_ partition); +use MDK::Common::System qw(getVarsFromSh); +use MDK::Common::Various qw(text2bool); extends qw( AdminPanel::Module ); @@ -77,6 +80,26 @@ has 'all_servers' => ( isa => 'ArrayRef', ); +has 'ifw_rules' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', +); + +has 'wdg_ifw' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', + default => sub { [] }, +); + +has 'wdg_servers' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', + default => sub { [] }, +); + has 'net' => ( is => 'rw', init_arg => undef, @@ -84,6 +107,25 @@ has 'net' => ( builder => '_initNet', ); +has 'aboutDialog' => ( + is => 'ro', + init_arg => undef, + isa => 'HashRef', + builder => '_setupAboutDialog', +); + +sub _setupAboutDialog { + my $self = shift(); + return { + name => "", + version => $VERSION, + credits => "Copyright (c) 2013-2015 by Matteo Pasotti", + license => "GPLv2", + description => "", + authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" + }; +} + sub _localeInitialize { my $self = shift(); @@ -102,48 +144,57 @@ sub _initAllServers { my $self = shift(); my @all_servers = ( { + id => 'www', name => $self->loc->N("Web Server"), pkg => 'apache apache-mod_perl boa lighttpd thttpd', ports => '80/tcp 443/tcp', }, { + id => 'dns', name => $self->loc->N("Domain Name Server"), pkg => 'bind dnsmasq mydsn', ports => '53/tcp 53/udp', }, { + id => 'ssh', name => $self->loc->N("SSH server"), pkg => 'openssh-server', ports => '22/tcp', }, { + id => 'ftp', name => $self->loc->N("FTP server"), pkg => 'ftp-server-krb5 wu-ftpd proftpd pure-ftpd', ports => '20/tcp 21/tcp', }, { + id => 'dhcp', name => $self->loc->N("DHCP Server"), pkg => 'dhcp-server udhcpd', ports => '67/udp 68/udp', hide => 1, }, { + id => 'mail', name => $self->loc->N("Mail Server"), pkg => 'sendmail postfix qmail exim', ports => '25/tcp 465/tcp 587/tcp', }, { + id => 'popimap', name => $self->loc->N("POP and IMAP Server"), pkg => 'imap courier-imap-pop', ports => '109/tcp 110/tcp 143/tcp 993/tcp 995/tcp', }, { + id => 'telnet', name => $self->loc->N("Telnet server"), pkg => 'telnet-server-krb5', ports => '23/tcp', hide => 1, }, { + id => 'nfs', name => $self->loc->N("NFS Server"), pkg => 'nfs-utils nfs-utils-clients', ports => '111/tcp 111/udp 2049/tcp 2049/udp ' . network::nfs::list_nfs_ports(), @@ -152,58 +203,68 @@ sub _initAllServers { restart => 'nfs-common nfs-server', }, { + id => 'smb', name => $self->loc->N("Windows Files Sharing (SMB)"), pkg => 'samba-server', ports => '137/tcp 137/udp 138/tcp 138/udp 139/tcp 139/udp 445/tcp 445/udp 1024:1100/tcp 1024:1100/udp', hide => 1, }, { + id => 'bacula', name => $self->loc->N("Bacula backup"), pkg => 'bacula-fd bacula-sd bacula-dir-common', ports => '9101:9103/tcp', hide => 1, }, { + id => 'syslog', name => $self->loc->N("Syslog network logging"), pkg => 'rsyslog syslog-ng', ports => '514/udp', hide => 1, }, { + id => 'cups', name => $self->loc->N("CUPS server"), pkg => 'cups', ports => '631/tcp 631/udp', hide => 1, }, { + id => 'mysql', name => $self->loc->N("MySQL server"), pkg => 'mysql', ports => '3306/tcp 3306/udp', hide => 1, }, { + id => 'postgresql', name => $self->loc->N("PostgreSQL server"), pkg => 'postgresql8.2 postgresql8.3', ports => '5432/tcp 5432/udp', hide => 1, }, { + id => 'echo', name => $self->loc->N("Echo request (ping)"), ports => '8/icmp', force_default_selection => 0, }, { + id => 'zeroconf', name => $self->loc->N("Network services autodiscovery (zeroconf and slp)"), ports => '5353/udp 427/udp', pkg => 'avahi cups openslp', }, { + id => 'bittorrent', name => $self->loc->N("BitTorrent"), ports => '6881:6999/tcp 6881:6999/udp', hide => 1, pkg => 'bittorrent deluge ktorrent transmission vuze rtorrent ctorrent', }, { + id => 'wmds', name => $self->loc->N("Windows Mobile device synchronization"), pkg => 'synce-hal', ports => '990/tcp 999/tcp 5678/tcp 5679/udp 26675/tcp', @@ -213,6 +274,18 @@ sub _initAllServers { return \@all_servers; } +sub _initIFW { + my $self = shift(); + my @ifw_rules = ( + { + id => 'psd', + name => $self->loc->N("Port scan detection"), + ifw_rule => 'psd', + }, + ); + return \@ifw_rules; +} + sub _initNet { my $self = shift(); my $net = {}; @@ -253,6 +326,29 @@ sub port2server { #============================================================= +=head2 to_ports + +=head3 INPUT + + $self: this object + + $unlisted: unlisted services + +=head3 DESCRIPTION + + This method converts from server definitions to port definitions + +=cut + +#============================================================= + +sub to_ports { + my ($servers, $unlisted) = @_; + join(' ', (map { $_->{ports} } @$servers), if_($unlisted, $unlisted)); +} + +#============================================================= + =head2 from_ports =head3 INPUT @@ -337,6 +433,172 @@ drakconnect before going any further."), } } +#============================================================= + +=head2 choose_watched_services + +=head3 INPUT + + $self: this object + + $disabled: boolean + + $servers: array of hashes representing servers + + $unlisted: array of hashes with the port not listed (???) + + $log_net_drop: network::shorewall log_net_drop attribute + +=head3 DESCRIPTION + + This method shows the main dialog to let users choose the allowed services + +=cut + +#============================================================= + +sub choose_watched_services { + my ($self, $servers, $unlisted) = @_; + + my @l = (@{$self->ifw_rules()}, @$servers, map { { ports => $_ } } split(' ', $unlisted)); + + my $enabled = 1; + $_->{ifw} = 1 foreach @l; + + $self->ask_WatchedServices({ + title => $self->loc->N("Interactive Firewall"), + icon => $network::shorewall::firewall_icon, + # if_(!$::isEmbedded, banner_title => N("Interactive Firewall")), + messages => + $self->loc->N("You can be warned when someone accesses to a service or tries to intrude into your computer. +Please select which network activities should be watched."), + }, + [ + { + text => $self->loc->N("Use Interactive Firewall"), val => \$enabled, type => 'bool' }, + map { + { + text => (exists $_->{name} ? $_->{name} : $_->{ports}), + val => \$_->{ifw}, + type => 'bool', disabled => sub { !$enabled }, + }, + } @l, + ]); + my ($rules, $ports) = partition { exists $_->{ifw_rule} } grep { $_->{ifw} } @l; + # set_ifw($in->do_pkgs, $enabled, [ map { $_->{ifw_rule} } @$rules ], to_ports($ports)); + + # return something to say that we are done ok + return ($rules, $ports); +} + +#============================================================= + +sub ask_WatchedServices { + my $self = shift; + + my ($dlg_data, + $items) = @_; + + my $old_title = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($dlg_data->{title}); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + $self->dialog($factory->createMainDialog()); + my $layout = $factory->createVBox($self->dialog); + + my $hbox_header = $factory->createHBox($layout); + my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); + my $headRight = $factory->createHBox($factory->createRight($hbox_header)); + + my $logoImage = $factory->createImage($headLeft, $dlg_data->{icon}); + my $labelAppDescription = $factory->createLabel($headRight,$dlg_data->{messages}); + $logoImage->setWeight($yui::YD_HORIZ,0); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + + my $widgetContainer = $factory->createVBox($hbox_content); + + + foreach my $item(@{$items}) + { + if(defined($item->{label})) + { + $factory->createLabel($factory->createLeft($factory->createHBox($widgetContainer)), $item->{label}); + } + elsif(defined($item->{text})) + { + my $ckbox = $factory->createCheckBox( + $factory->createLeft($factory->createHBox($widgetContainer)), + $item->{text}, + ${$item->{val}} + ); + $ckbox->setNotify(1); + push @{$self->wdg_ifw()}, { + id => $item->{id}, + widget => \$ckbox, + value => $item->{val}, + }; + $ckbox->DISOWN(); + } + } + + my $hbox_foot = $factory->createHBox($layout); + my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); + my $vbox_foot_right = $factory->createVBox($factory->createRight($hbox_foot)); + my $aboutButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("OK")); + + # main loop + while(1) { + my $event = $self->dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + ### Buttons and widgets ### + my $widget = $event->widget(); + + # loop on every checkbox representing servers + foreach my $server(@{$self->wdg_servers()}) + { + if($widget == ${$server->{widget}}) + { + ${$server->{value}} = !${$server->{value}}; + } + } + + if ($widget == $cancelButton) { + last; + }elsif ($widget == $aboutButton) { + my $abtdlg = $self->aboutDialog(); + $abtdlg->{name} = $dlg_data->{title}; + $abtdlg->{description} = $self->loc->N("Graphical manager for interactive firewall rules"); + $self->sh_gui->AboutDialog($abtdlg + ); + }elsif ($widget == $okButton) { + last; + } + } + } + + $self->dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($old_title); + + return 1; +} + + #============================================================= =head2 choose_allowed_services @@ -394,47 +656,33 @@ Have a look at /etc/services for information."), { label => $self->loc->N("Which services would you like to allow the Internet to connect to?"), title => 1 }, if_($self->net()->{PROFILE} && network::network::netprofile_count() > 0, { label => $self->loc->N("Those settings will be saved for the network profile %s", $self->net()->{PROFILE}) }), { text => $self->loc->N("Everything (no firewall)"), val => \$disabled, type => 'bool' }, - (map { { text => $_->{name}, val => \$_->{on}, type => 'bool', disabled => sub { $disabled } } } @l), + (map { { text => $_->{name}, val => \$_->{on}, type => 'bool', disabled => sub { $disabled }, id => $_->{id} } } @l), { label => $self->loc->N("Other ports"), val => \$unlisted, advanced => 1, disabled => sub { $disabled } }, { text => $self->loc->N("Log firewall messages in system logs"), val => \$log_net_drop, type => 'bool', advanced => 1, disabled => sub { $disabled } }, ]; - $self->ask_AllowedServices($dialog_data, $items) or return; + $self->ask_AllowedServices($dialog_data, $items); + for my $server(@{$self->wdg_servers()}) + { + for my $k(keys @l) + { + if(defined($l[$k]->{id}) && defined($server->{id})) + { + if($l[$k]->{id} eq $server->{id}) + { + $l[$k]->{on} = ${$server->{value}}; + last; + } + } + } + } + return ($disabled, [ grep { $_->{on} } @l ], $unlisted, $log_net_drop); } #============================================================= -=head2 start - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method extends Module::start and is invoked to - start host manager - -=cut - -#============================================================= - -sub start { - my $self = shift; - - $self->all_servers($self->_initAllServers()); - - - - my ($disabled, $servers, $unlisted, $log_net_drop) = $self->get_conf(undef) or return; - ($disabled, $servers, $unlisted, $log_net_drop) = $self->choose_allowed_services($disabled, $servers, $unlisted, $log_net_drop) or return; - -}; - -#============================================================= - sub ask_AllowedServices { my $self = shift; @@ -469,14 +717,25 @@ sub ask_AllowedServices { { if(defined($item->{label})) { - $factory->createLabel($widgetContainer, $item->{label}); + $factory->createLabel($factory->createLeft($factory->createHBox($widgetContainer)), $item->{label}); } elsif(defined($item->{text})) { - $factory->createLabel($widgetContainer, $item->{text} . " - ". $item->{val} . " - " . $item->{type}); + my $ckbox = $factory->createCheckBox( + $factory->createLeft($factory->createHBox($widgetContainer)), + $item->{text}, + ${$item->{val}} + ); + $ckbox->setNotify(1); + push @{$self->wdg_servers()}, { + id => $item->{id}, + widget => \$ckbox, + value => $item->{val}, + }; + $ckbox->DISOWN(); } } - + my $hbox_foot = $factory->createHBox($layout); my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); my $vbox_foot_right = $factory->createVBox($factory->createRight($hbox_foot)); @@ -494,32 +753,124 @@ sub ask_AllowedServices { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { -### Buttons and widgets ### + ### Buttons and widgets ### my $widget = $event->widget(); + + # loop on every checkbox representing servers + foreach my $server(@{$self->wdg_servers()}) + { + if($widget == ${$server->{widget}}) + { + ${$server->{value}} = !${$server->{value}}; + } + } + if ($widget == $cancelButton) { last; }elsif ($widget == $aboutButton) { - $self->sh_gui->AboutDialog({ - name => $dlg_data->{title}, - version => $VERSION, - credits => "Copyright (c) 2013-2015 by Matteo Pasotti", - license => "GPLv2", - description => $self->loc->N("Graphical manager for firewall rules"), - authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" - } + my $abtdlg = $self->aboutDialog(); + $abtdlg->{name} = $dlg_data->{title}; + $abtdlg->{description} = $self->loc->N("Graphical manager for firewall rules"); + $self->sh_gui->AboutDialog($abtdlg ); }elsif ($widget == $okButton) { - # write changes - return last; } } } - $self->dialog->destroy() ; + $self->dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($old_title); + + return 1; +} + +#============================================================= + +=head2 set_ports + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= + +sub set_ports { + my ($disabled, $ports, $log_net_drop) = @_; + + if (!$disabled || -x "$::prefix/sbin/shorewall") { + # $do_pkgs->ensure_files_are_installed([ [ qw(shorewall shorewall) ], [ qw(shorewall-ipv6 shorewall6) ] ], $::isInstall) or return; + my $shorewall = network::shorewall::read(!$disabled); + if (!$shorewall) { + print ("unable to read shorewall configuration, skipping installation"); + return; + } + + $shorewall->{disabled} = $disabled; + $shorewall->{ports} = $ports; + $shorewall->{log_net_drop} = $log_net_drop; + print ($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); + network::shorewall::write($shorewall, undef); + } } +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= + +sub start { + my $self = shift; + + my @server = (); + $self->wdg_servers(@server); + + # init servers definitions + $self->all_servers($self->_initAllServers()); + + # initialize ifw_rules here + $self->ifw_rules($self->_initIFW()); + + my ($disabled, $servers, $unlisted, $log_net_drop) = $self->get_conf(undef) or return; + ($disabled, $servers, $unlisted, $log_net_drop) = $self->choose_allowed_services($disabled, $servers, $unlisted, $log_net_drop) or return; + + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + + if (!$disabled && (!defined($global_settings{IFW}) || text2bool($global_settings{IFW}))) { + $self->choose_watched_services($servers, $unlisted) or return; + } + + # preparing services when required ( look at $self->all_servers() ) + foreach (@$servers) { + exists $_->{prepare} and $_->{prepare}(); + } + + my $ports = $self->to_ports($servers, $unlisted); + + $self->set_ports($disabled, $ports, $log_net_drop) or return; + +}; + 1; -- cgit v1.2.1 From 73809416f7cfc49b4625cb126be961f19154f932 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Tue, 6 Jan 2015 00:57:47 +0100 Subject: drop common --- lib/AdminPanel/Shared/Firewall.pm | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/AdminPanel/Shared/Firewall.pm b/lib/AdminPanel/Shared/Firewall.pm index 2638ff87..d8ae4edb 100644 --- a/lib/AdminPanel/Shared/Firewall.pm +++ b/lib/AdminPanel/Shared/Firewall.pm @@ -24,8 +24,6 @@ use diagnostics; use utf8; use lib qw(/usr/lib/libDrakX); -# WARNING: using common -use common; use network::nfs; use network::network; use network::shorewall; -- cgit v1.2.1 From 283363de614cc6ce8d729aa5d0df1c295dbc623b Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:31:19 +0100 Subject: added manawall and its modules --- MANIFEST | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MANIFEST b/MANIFEST index 4dd184e3..71044206 100644 --- a/MANIFEST +++ b/MANIFEST @@ -41,6 +41,7 @@ lib/AdminPanel/Module/LogViewer.pm lib/AdminPanel/Module/Proxy.pm lib/AdminPanel/Module/Services.pm lib/AdminPanel/Module/Users.pm +lib/AdminPanel/Module/Firewall.pm lib/AdminPanel/Privileges.pm lib/AdminPanel/rpmdragora.pm lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm @@ -63,6 +64,8 @@ lib/AdminPanel/Shared/RunProgram.pm lib/AdminPanel/Shared/Services.pm lib/AdminPanel/Shared/TimeZone.pm lib/AdminPanel/Shared/Users.pm +lib/AdminPanel/Shared/Firewall.pm +lib/AdminPanel/Shared/Shorewall.pm Makefile.PL MANIFEST This list of files MODULE_HACKING @@ -83,6 +86,7 @@ scripts/manalog scripts/manaproxy scripts/manaservice scripts/manauser +scripts/manawall scripts/mpan share/images/Blank16x16.png share/images/Check.png -- cgit v1.2.1 From c31b1f2edd43d60416ccdbdc76d0d87e297efd7c Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:32:12 +0100 Subject: added shared module for shorewall --- lib/AdminPanel/Shared/Shorewall.pm | 227 +++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 lib/AdminPanel/Shared/Shorewall.pm diff --git a/lib/AdminPanel/Shared/Shorewall.pm b/lib/AdminPanel/Shared/Shorewall.pm new file mode 100644 index 00000000..af18d60e --- /dev/null +++ b/lib/AdminPanel/Shared/Shorewall.pm @@ -0,0 +1,227 @@ +package AdminPanel::Shared::Shorewall; # $Id: shorewall.pm 254244 2009-03-18 22:54:32Z eugeni $ + +use lib qw(/usr/lib/libDrakX); # helps perl_checker +use detect_devices; +use network::network; +use AdminPanel::Shared::RunProgram; +use MDK::Common::Func qw(if_ partition); +use MDK::Common::File qw(cat_); +use List::Util qw(any); +use List::MoreUtils qw(uniq); +use log; + +my $shorewall_root = "/etc/shorewall"; +our $firewall_icon = $::isInstall ? 'banner-security' : '/usr/share/mcc/themes/default/firewall-mdk.png'; + +sub check_iptables() { + -f "$::prefix/etc/sysconfig/iptables" || + $::isStandalone && do { + system('modprobe iptable_nat'); + -x '/sbin/iptables' && listlength(`/sbin/iptables -t nat -nL`) > 8; + }; +} + +sub set_config_file { + my ($file, $ver, @l) = @_; + + my $done; + substInFile { + my $last_line = /^#LAST LINE/ && $_; + if (!$done && ($last_line || eof)) { + $_ = join('', map { join("\t", @$_) . "\n" } @l); + $_ .= $last_line if $last_line; + $done = 1; + } else { + $_ = '' unless + /^#/ || $file eq 'rules' && /^SECTION/; + } + } "$::prefix${shorewall_root}${ver}/$file"; +} + +sub get_config_file { + my ($file, $o_ver) = @_; + map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix${shorewall_root}${o_ver}/$file"); +} + +# Note: Called from drakguard and drakfirewall.pm... +# Deliberately not adding shorewall6 support here for now +sub set_in_file { + my ($file, $enabled, @list) = @_; + my $done; + substInFile { + my $last_line = /^#LAST LINE/ && $_; + foreach my $l (@list) { s|^$l\n|| } + if (!$done && $enabled && ($last_line || eof)) { + $_ = join('', map { "$_\n" } @list); + $_ .= $last_line if $last_line; + $done = 1; + } + } "$::prefix${shorewall_root}/$file"; +} + +sub dev_to_shorewall { + my ($dev) = @_; + $dev =~ /^ippp/ && "ippp+" || + $dev =~ /^ppp/ && "ppp+" || + $dev; +} + +sub get_net_zone_interfaces { + my ($interfacesfile, $_net, $all_intf) = @_; + #- read shorewall configuration first + my @interfaces = map { $_->[1] } grep { $_->[0] eq 'net' } $interfacesfile; + #- else try to find the best interface available + @interfaces ? @interfaces : @{$all_intf || []}; +} + +sub add_interface_to_net_zone { + my ($conf, $interface) = @_; + if (!member($interface, @{$conf->{net_zone}})) { + push @{$conf->{net_zone}}, $interface; + @{$conf->{loc_zone}} = grep { $_ ne $interface } @{$conf->{loc_zone}}; + } +} + +sub read_ { + my ($o_ver) = @_; + my $ver = ''; + $ver = $o_ver if $o_ver; + #- read old rules file if config is not moved to rules.drakx yet + my @rules = get_config_file(-f "$::prefix${shorewall_root}${ver}/rules.drakx" ? 'rules.drakx' : 'rules', $ver); + require services; + my %conf = (disabled => !services::starts_on_boot("shorewall${ver}"), + version => $ver, + ports => join(' ', map { + my $e = $_; + map { "$_/$e->[3]" } split(',', $e->[4]); + } grep { $_->[0] eq 'ACCEPT' && $_->[1] eq 'net' } @rules), + ); + push @{$conf{accept_local_users}{$_->[4]}}, $_->[8] foreach grep { $_->[0] eq 'ACCEPT+' } @rules; + $conf{redirects}{$_->[3]}{$_->[4]} = $_->[2] foreach grep { $_->[0] eq 'REDIRECT' } @rules; + + if (my ($e) = get_config_file('masq', $ver)) { + ($conf{masq}{net_interface}, $conf{masq}{subnet}) = @$e; + } + + my @policy = get_config_file('policy', $ver); + $conf{log_net_drop} = @policy ? (any { $_->[0] eq 'net' && $_->[1] eq 'all' && $_->[2] eq 'DROP' && $_->[3] } @policy) : 1; + + return \%conf; + + # get_zones(\%conf); + # get_config_file('zones', $ver) && \%conf; +} + +sub ports_by_proto { + my ($ports) = @_; + my %ports_by_proto; + foreach (split ' ', $ports) { + m!^(\d+(?::\d+)?)/(udp|tcp|icmp)$! or die "bad port $_\n"; + push @{$ports_by_proto{$2}}, $1; + } + \%ports_by_proto; +} + +sub write { + my ($conf, $o_in) = @_; + my $ver = $conf->{version} || ''; + my $use_pptp = any { /^ppp/ && cat_("$::prefix/etc/ppp/peers/$_") =~ /pptp/ } @{$conf->{net_zone}}; + my $ports_by_proto = ports_by_proto($conf->{ports}); + my $has_loc_zone = to_bool(@{$conf->{loc_zone} || []}); + + my ($include_drakx, $other_rules) = partition { $_ eq "INCLUDE\trules.drakx\n" } grep { !/^(#|SECTION)/ } cat_("$::prefix${shorewall_root}${ver}/rules"); + #- warn if the config is already in rules.drakx and additionnal rules are configured + if (!is_empty_array_ref($include_drakx) && !is_empty_array_ref($other_rules)) { + my %actions = ( + keep => N("Keep custom rules"), + drop => N("Drop custom rules"), + ); + my $action = 'keep'; + !$o_in || $o_in->ask_from_( + { + messages => N("Your firewall configuration has been manually edited and contains +rules that may conflict with the configuration that has just been set up. +What do you want to do?"), + title => N("Firewall"), + icon => 'banner-security', + }, + [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { $actions{$_[0]} } } ]) or return; + #- reset the rules files if the user has chosen to drop modifications + undef $include_drakx if $action eq 'drop'; + } + + my $interface_settings = sub { + my ($zone, $interface) = @_; + [ $zone, $interface, 'detect', if_(detect_devices::is_bridge_interface($interface), 'bridge') ]; + }; + + set_config_file('zones', $ver, + if_($has_loc_zone, [ 'loc', 'ipv' . ($ver || '4') ]), + [ 'net', 'ipv' . ($ver || '4') ], + [ 'fw', 'firewall' ], + ); + set_config_file('interfaces', $ver, + (map { $interface_settings->('net', $_) } @{$conf->{net_zone}}), + (map { $interface_settings->('loc', $_) } @{$conf->{loc_zone} || []}), + ); + set_config_file('policy', $ver, + if_($has_loc_zone, [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), + [ 'fw', 'net', 'ACCEPT' ], + [ 'net', 'all', 'DROP', if_($conf->{log_net_drop}, 'info') ], + [ 'all', 'all', 'REJECT', 'info' ], + ); + if (is_empty_array_ref($include_drakx)) { + #- make sure the rules.drakx config is read, erasing user modifications + set_config_file('rules', $ver, [ 'INCLUDE', 'rules.drakx' ]); + } + output_with_perm("$::prefix${shorewall_root}${ver}/" . 'rules.drakx', 0600, map { join("\t", @$_) . "\n" } ( + if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'tcp', '1723' ]), + if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'gre' ]), + (map_each { [ 'ACCEPT', 'net', 'fw', $::a, join(',', @$::b), '-' ] } %$ports_by_proto), + (map_each { + if_($::b, map { [ 'ACCEPT+', 'fw', 'net', 'tcp', $::a, '-', '-', '-', $_ ] } @$::b); + } %{$conf->{accept_local_users}}), + (map { + my $proto = $_; + #- WARNING: won't redirect ports from the firewall system if a local zone exists + #- set redirect_fw_only to workaround + map_each { + map { [ 'REDIRECT', $_, $::b, $proto, $::a, '-' ] } 'fw', if_($has_loc_zone, 'loc'); + } %{$conf->{redirects}{$proto}}; + } keys %{$conf->{redirects}}), + )); + set_config_file('masq', $ver, if_(exists $conf->{masq}, [ $conf->{masq}{net_interface}, $conf->{masq}{subnet} ])); + + require services; + if ($conf->{disabled}) { + services::disable('shorewall', $::isInstall); + run_program::rooted($::prefix, '/sbin/shorewall', 'clear') unless $::isInstall; + } else { + services::enable('shorewall', $::isInstall); + } +} + +sub set_redirected_ports { + my ($conf, $proto, $dest, @ports) = @_; + if (@ports) { + $conf->{redirects}{$proto}{$_} = $dest foreach @ports; + } else { + my $r = $conf->{redirects}{$proto}; + @ports = grep { $r->{$_} eq $dest } keys %$r; + delete $r->{$_} foreach @ports; + } +} + +sub update_interfaces_list { + my ($o_intf) = @_; + if (!$o_intf || !member($o_intf, map { $_->[1] } get_config_file('interfaces'))) { + my $shorewall = network::shorewall::read(); + $shorewall && !$shorewall->{disabled} and network::shorewall::write($shorewall); + } + if (!$o_intf || !member($o_intf, map { $_->[1] } get_config_file('interfaces', 6))) { + my $shorewall6 = network::shorewall::read(undef, 6); + $shorewall6 && !$shorewall6->{disabled} and network::shorewall::write($shorewall6); + } +} + +1; -- cgit v1.2.1 From b4eeab6d7f05dab5bbd973073bbdbab694171659 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:32:52 +0100 Subject: added Moose::AutoBox and MDK::Common::Various prereq --- Makefile.PL | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.PL b/Makefile.PL index 3bd403b3..ebe6ee4c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -25,6 +25,7 @@ WriteMakefile( }, PREREQ_PM => { "Moose" => 0, + "Moose::Autobox" => 0, "Config::Auto" => 0, "Config::Hosts" => 0, "Config::Tiny" => 0, @@ -52,6 +53,7 @@ WriteMakefile( "MDK::Common::Func" => 0, "MDK::Common::System" => 0, "MDK::Common::String" => 0, + "MDK::Common::Various" => 0, "Net::DBus" => 0, "URPM" => 0, "Glib" => 0, -- cgit v1.2.1 From 40e47168ae09b43615015cc546d52bdb9a9a01d9 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:35:41 +0100 Subject: added ask_TwoConfigurableButtons and ask_multiple_fromList shared methods --- lib/AdminPanel/Shared/GUI.pm | 180 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/lib/AdminPanel/Shared/GUI.pm b/lib/AdminPanel/Shared/GUI.pm index a28df033..bdbc1fcf 100644 --- a/lib/AdminPanel/Shared/GUI.pm +++ b/lib/AdminPanel/Shared/GUI.pm @@ -323,6 +323,66 @@ sub ask_YesOrNo { } +#============================================================= + +=head2 ask_TwoConfigurableButtons + +=head3 INPUT + +$info: HASH, information to be passed to the dialog. + title => dialog title + text => string to be swhon into the dialog + richtext => 1 if using rich text + button_one => caption for the first button + button_two => caption for the second button + default_button => (optional) 1: "First button" + +=head3 OUTPUT + + 0: "Button One Caption" button has been pressed + 1: "Button Two Caption" button has been pressed + +=head3 DESCRIPTION + +This function create a two-buttons dialog with a 'title', a +question 'text' and a label for each button passed as parameters. + +=cut + +#============================================================= + +sub ask_TwoConfigurableButtons { + my ($self, $info) = @_; + + return 0 if ( ! $info ); + + my $retVal = 0; + yui::YUI::widgetFactory; + my $factory = yui::YExternalWidgets::externalWidgetFactory("mga"); + $factory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($factory); + my $dlg = $factory->createDialogBox($yui::YMGAMessageBox::B_TWO); + + $dlg->setTitle($info->{title}) if (exists $info->{title}); + my $rt = (exists $info->{richtext}) ? $info->{richtext} : 0; + $dlg->setText($info->{text}, $rt) if (exists $info->{text}); + + $dlg->setButtonLabel($info->{button_one}, $yui::YMGAMessageBox::B_ONE ); + $dlg->setButtonLabel($info->{button_two}, $yui::YMGAMessageBox::B_TWO); + if (exists $info->{default_button} && $info->{default_button} == 1) { + $dlg->setDefaultButton($yui::YMGAMessageBox::B_ONE); + } + else { + $dlg->setDefaultButton($yui::YMGAMessageBox::B_TWO); + } + $dlg->setMinSize(50, 5); + + $retVal = $dlg->show() == $yui::YMGAMessageBox::B_ONE ? 1 : 0; + + $dlg = undef; + + return $retVal; +} + #============================================================= =head2 arrayListToYItemCollection @@ -467,6 +527,126 @@ sub ask_fromList { #============================================================= +=head2 ask_multiple_fromList + +=head3 INPUT + +$info: HASH, information to be passed to the dialog. + title => dialog title + header => combobox header + default_item => selected item if any + list => item list + default_button => (optional) 1: Select (any other values Cancel) + +=head3 OUTPUT + + undef: if Cancel button has been pressed + selected item: if Select button has been pressed + +=head3 DESCRIPTION + +This function create a dialog with variable checkboxes in which to +choose the items from a given list. + +Warning: to use only for a reduced set of items because of no scroll available + +=cut + +#============================================================= + +sub ask_multiple_fromList { + my ($self, $info) = @_; + + die "Missing dialog information" if (!$info); + die "Title is mandatory" if (! exists $info->{title}); + die "Header is mandatory" if (! exists $info->{header}); + die "List is mandatory" if (! exists $info->{list} ); + die "At least one element is mandatory into list" if (scalar(@{$info->{list}}) < 1); + + my @selections = (); + my $factory = yui::YUI::widgetFactory; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($info->{title}); + + my $dlg = $factory->createPopupDialog($yui::YDialogNormalColor); + my $layout = $factory->createVBox($dlg); + + my @ckbox_array = (); + + for my $item(@{$info->{list}}) + { + my $ckbox = $factory->createCheckBox( + $factory->createLeft($factory->createHBox($layout)), + $item->{text}, + ${$item->{val}} + ); + $ckbox->setNotify(1); + push @ckbox_array, { + widget => \$ckbox, + text => $item, + value => $ckbox->value(), + }; + $ckbox->DISOWN(); + } + + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $selectButton = $factory->createPushButton($hbox, $self->loc->N("Select")); + my $cancelButton = $factory->createPushButton($hbox, $self->loc->N("Cancel")); + + if (exists $info->{default_button} ) { + my $dflBtn = ($info->{default_button} == 1) ? $selectButton : $cancelButton; + $dlg->setDefaultButton($selectButton); + } + + while (1) { + my $event = $dlg->waitForEvent(); + + my $eventType = $event->eventType(); + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + for my $ckbox (@ckbox_array) + { + if($widget == ${$ckbox->{widget}}) + { + ${$ckbox->{value}} = !${$ckbox->{value}}; + } + } + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $selectButton) { + foreach my $ckbox (@ckbox_array) + { + if($ckbox->{value} == 1) + { + push @selections, $ckbox->{text}; + } + } + last; + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + + return @selections; +} + +#============================================================= + =head2 AboutDialog =head3 INPUT -- cgit v1.2.1 From 87f7dca4f7bfb8b74acb8415c0c2b8ad6588765e Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:42:24 +0100 Subject: moved sub get_zones from Shared::Shorewall to this module because it requires user interaction (impacts sub Shorewall::read) --- lib/AdminPanel/Module/Firewall.pm | 138 ++++++++++++++++++++++++++++++++++---- 1 file changed, 125 insertions(+), 13 deletions(-) diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm index d9c8ff54..61bb2588 100644 --- a/lib/AdminPanel/Module/Firewall.pm +++ b/lib/AdminPanel/Module/Firewall.pm @@ -30,14 +30,15 @@ use yui; use AdminPanel::Shared qw(trim); use AdminPanel::Shared::GUI; use AdminPanel::Shared::Firewall; - -use List::Util qw(any); -use List::MoreUtils qw(uniq); +use AdminPanel::Shared::Shorewall; use MDK::Common::Func qw(if_ partition); use MDK::Common::System qw(getVarsFromSh); use MDK::Common::Various qw(text2bool); +use List::Util qw(any); +use List::MoreUtils qw(uniq); + extends qw( AdminPanel::Module ); has '+icon' => ( @@ -343,7 +344,7 @@ sub port2server { #============================================================= sub to_ports { - my ($servers, $unlisted) = @_; + my ($self, $servers, $unlisted) = @_; join(' ', (map { $_->{ports} } @$servers), if_($unlisted, $unlisted)); } @@ -405,10 +406,12 @@ sub get_conf { my $self = shift(); my ($disabled, $o_ports) = @_; my $possible_servers = undef; + my $conf = AdminPanel::Shared::Shorewall::read_(); + my $shorewall = AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf; if ($o_ports) { return ($disabled, from_ports($o_ports)); - } elsif (my $shorewall = network::shorewall::read()) { + } elsif ($shorewall) { # WARNING: this condition fails (the method fails) # if manawall runs as unprivileged user # cause it can't read the interfaces file @@ -467,7 +470,7 @@ sub choose_watched_services { $self->ask_WatchedServices({ title => $self->loc->N("Interactive Firewall"), - icon => $network::shorewall::firewall_icon, + icon => $AdminPanel::Shared::Shorewall::firewall_icon, # if_(!$::isEmbedded, banner_title => N("Interactive Firewall")), messages => $self->loc->N("You can be warned when someone accesses to a service or tries to intrude into your computer. @@ -632,7 +635,7 @@ sub choose_allowed_services { my $dialog_data = { title => $self->loc->N("Firewall"), - icon => $network::shorewall::firewall_icon, + icon => $AdminPanel::Shared::Shorewall::firewall_icon, # if_(!$::isEmbedded, banner_title => $self->loc->N("Firewall")), banner_title => $self->loc->N("Firewall"), advanced_messages => $self->loc->N("You can enter miscellaneous ports. @@ -787,6 +790,40 @@ sub ask_AllowedServices { return 1; } +sub get_zones { + my $self = shift(); + my $confref = shift(); + my $conf = ${$confref}; + my $interfacesfile = AdminPanel::Shared::Shorewall::get_config_file('interfaces', $conf->{version} || ''); + network::network::read_net_conf($self->net()); + #- find all interfaces but alias interfaces + my @all_intf = grep { !/:/ } uniq(keys(%{$self->net()->{ifcfg}}), detect_devices::get_net_interfaces()); + my %net_zone = map { $_ => undef } @all_intf; + $net_zone{$_} = 1 foreach AdminPanel::Shared::Shorewall::get_net_zone_interfaces($interfacesfile, $self->net(), \@all_intf); + my @retvals = $self->sh_gui->ask_multiple_fromList({ + title => $self->loc->N("Firewall configuration"), + header => $self->loc->N("Please select the interfaces that will be protected by the firewall. + +All interfaces directly connected to Internet should be selected, +while interfaces connected to a local network may be unselected. + +If you intend to use Mageia Internet Connection sharing, +unselect interfaces which will be connected to local network. + +Which interfaces should be protected? +"), + list => [ + map { + { + text => network::tools::get_interface_description($self->net(), $_), + val => \$net_zone{$_}, + type => 'bool' + }; + } (sort keys %net_zone) ] + }); + ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone; +} + #============================================================= =head2 set_ports @@ -805,11 +842,13 @@ sub ask_AllowedServices { #============================================================= sub set_ports { - my ($disabled, $ports, $log_net_drop) = @_; - + my ($self, $disabled, $ports, $log_net_drop) = @_; + if (!$disabled || -x "$::prefix/sbin/shorewall") { # $do_pkgs->ensure_files_are_installed([ [ qw(shorewall shorewall) ], [ qw(shorewall-ipv6 shorewall6) ] ], $::isInstall) or return; - my $shorewall = network::shorewall::read(!$disabled); + my $conf = AdminPanel::Shared::Shorewall::read_(!$disabled); + $self->get_zones(\$conf); + my $shorewall = AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf; if (!$shorewall) { print ("unable to read shorewall configuration, skipping installation"); return; @@ -819,7 +858,18 @@ sub set_ports { $shorewall->{ports} = $ports; $shorewall->{log_net_drop} = $log_net_drop; print ($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); - network::shorewall::write($shorewall, undef); + + my $action = 'keep'; + # $fake_in->ask_from_({ + # messages => $self->loc->N("Your firewall configuration has been manually edited and contains +#rules that may conflict with the configuration that has just been set up. +#What do you want to do?"), + # title => $self->loc->N("Firewall"), + # icon => 'banner-security', + # }, + # [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { } } ]); + + # AdminPanel::Shared::Shorewall::write($shorewall, $fake_in); } } @@ -866,11 +916,73 @@ sub start { foreach (@$servers) { exists $_->{prepare} and $_->{prepare}(); } - + my $ports = $self->to_ports($servers, $unlisted); - + $self->set_ports($disabled, $ports, $log_net_drop) or return; }; +sub ask_from_ { + my $self = shift(); + + my ($dlg_data, + $items) = @_; + + my @buttons = (); + my @list = (); + my $val = undef; + + foreach my $item(@{$items}) + { + push @list, { + text => $item->{text}, + value => ${$item->{val}}, + }; + } + + + my @retval = $self->sh_gui->ask_multiple_fromList({ + title => $dlg_data->{title}, + header => $dlg_data->{messages}, + list => \@list}); + use Data::Dumper; + print Dumper(@retval); + + return @retval; +} +# sub ask_from_ { +# my $self = shift(); +# +# my ($dlg_data, +# $items) = @_; +# +# my @buttons = (); +# my $val = undef; +# +# foreach my $item(@{$items}) +# { +# push @buttons, { +# caption => $item->{text}, +# value => \$item->{val}, +# }; +# } +# +# if($self->sh_gui->ask_fromList({ +# title => $dlg_data->{title}, +# text => $dlg_data->{messages}, +# richtext => 1, +# button_one => $buttons[0]->{caption}, +# button_two => $buttons[1]->{caption}, +# })) +# { +# $val = $buttons[0]->{caption}; +# } +# else +# { +# $val = $buttons[1]->{caption}; +# } +# return 1; +# } + 1; -- cgit v1.2.1 From f0499a9f135c2559bdbab380cb934e4bb105eb80 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:49:11 +0100 Subject: drop network::shorewall; use network::tools --- lib/AdminPanel/Shared/Firewall.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AdminPanel/Shared/Firewall.pm b/lib/AdminPanel/Shared/Firewall.pm index d8ae4edb..ac447770 100644 --- a/lib/AdminPanel/Shared/Firewall.pm +++ b/lib/AdminPanel/Shared/Firewall.pm @@ -26,7 +26,7 @@ use utf8; use lib qw(/usr/lib/libDrakX); use network::nfs; use network::network; -use network::shorewall; +use network::tools; sub _initialize { my $self = shift(); -- cgit v1.2.1 From 48edd028fc3d2c72866fbee9d1f1bc91ddf11568 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 12:50:02 +0100 Subject: added brief comment explaining how to read shorewall conf from now on --- lib/AdminPanel/Shared/Shorewall.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/AdminPanel/Shared/Shorewall.pm b/lib/AdminPanel/Shared/Shorewall.pm index af18d60e..f043e86d 100644 --- a/lib/AdminPanel/Shared/Shorewall.pm +++ b/lib/AdminPanel/Shared/Shorewall.pm @@ -108,8 +108,15 @@ sub read_ { return \%conf; + # get_zones has been moved to AdminPanel::Module::Firewall cause it requires + # user interaction thus it should be logically separated by shorewall # get_zones(\%conf); # get_config_file('zones', $ver) && \%conf; + # consequently, to read shorewall conf + # you have to do something like this now (within Module::Firewall) + # my $conf = AdminPanel::Shared::Shorewall::read_(); + # OPTIONAL: my $self->get_zones(\$conf) + # my $shorewall = AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf; } sub ports_by_proto { -- cgit v1.2.1 From b4ae57d85a422cbc8f909123925b0b5a3a03fdc2 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 17:21:11 +0100 Subject: - added set_ifw method (still no do_pkgs support) - use MDK::Common::Various/DataStructure/File - choose_watched_services: choices are now properly stored - exit on cancel - implemented Shorewall::write_ call to effectively store configurations --- lib/AdminPanel/Module/Firewall.pm | 104 +++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm index 61bb2588..c24c7cd6 100644 --- a/lib/AdminPanel/Module/Firewall.pm +++ b/lib/AdminPanel/Module/Firewall.pm @@ -34,7 +34,9 @@ use AdminPanel::Shared::Shorewall; use MDK::Common::Func qw(if_ partition); use MDK::Common::System qw(getVarsFromSh); -use MDK::Common::Various qw(text2bool); +use MDK::Common::Various qw(text2bool to_bool); +use MDK::Common::DataStructure qw(intersection); +use MDK::Common::File qw(substInFile output_with_perm); use List::Util qw(any); use List::MoreUtils qw(uniq); @@ -407,7 +409,7 @@ sub get_conf { my ($disabled, $o_ports) = @_; my $possible_servers = undef; my $conf = AdminPanel::Shared::Shorewall::read_(); - my $shorewall = AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf; + my $shorewall = (AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf); if ($o_ports) { return ($disabled, from_ports($o_ports)); @@ -436,6 +438,31 @@ drakconnect before going any further."), } } +sub set_ifw { + # my ($do_pkgs, $enabled, $rules, $ports) = @_; + my $self = shift(); + my ($enabled, $rules, $ports) = @_; + if ($enabled) { + my $ports_by_proto = AdminPanel::Shared::Shorewall::ports_by_proto($ports); + output_with_perm("$::prefix/etc/ifw/rules", 0644, + (map { ". /etc/ifw/rules.d/$_\n" } @$rules), + map { + my $proto = $_; + map { + my $multiport = /:/ && " -m multiport"; + "iptables -A Ifw -m conntrack --ctstate NEW -p $proto$multiport --dport $_ -j IFWLOG --log-prefix NEW\n"; + } @{$ports_by_proto->{$proto}}; + } intersection([ qw(tcp udp) ], [ keys %$ports_by_proto ]), + ); + } + + substInFile { + undef $_ if m!^INCLUDE /etc/ifw/rules|^iptables -I INPUT 2 -j Ifw!; + } "$::prefix/etc/shorewall/start"; + AdminPanel::Shared::Shorewall::set_in_file('start', $enabled, "INCLUDE /etc/ifw/start", "INCLUDE /etc/ifw/rules", "iptables -I INPUT 1 -j Ifw"); + AdminPanel::Shared::Shorewall::set_in_file('stop', $enabled, "iptables -D INPUT -j Ifw", "INCLUDE /etc/ifw/stop"); +} + #============================================================= =head2 choose_watched_services @@ -483,12 +510,31 @@ Please select which network activities should be watched."), { text => (exists $_->{name} ? $_->{name} : $_->{ports}), val => \$_->{ifw}, - type => 'bool', disabled => sub { !$enabled }, + type => 'bool', + disabled => sub { !$enabled }, + id => $_->{id}, }, } @l, ]); + + for my $server(@{$self->wdg_ifw()}) + { + for my $k(keys @l) + { + if(defined($l[$k]->{id}) && defined($server->{id})) + { + if($l[$k]->{id} eq $server->{id}) + { + $l[$k]->{ifw} = ${$server->{value}}; + last; + } + } + } + } + my ($rules, $ports) = partition { exists $_->{ifw_rule} } grep { $_->{ifw} } @l; - # set_ifw($in->do_pkgs, $enabled, [ map { $_->{ifw_rule} } @$rules ], to_ports($ports)); + + $self->set_ifw($enabled, [ map { $_->{ifw_rule} } @$rules ], to_ports($ports)); # return something to say that we are done ok return ($rules, $ports); @@ -571,7 +617,7 @@ sub ask_WatchedServices { my $widget = $event->widget(); # loop on every checkbox representing servers - foreach my $server(@{$self->wdg_servers()}) + foreach my $server(@{$self->wdg_ifw()}) { if($widget == ${$server->{widget}}) { @@ -580,6 +626,7 @@ sub ask_WatchedServices { } if ($widget == $cancelButton) { + exit(); last; }elsif ($widget == $aboutButton) { my $abtdlg = $self->aboutDialog(); @@ -745,7 +792,7 @@ sub ask_AllowedServices { my $aboutButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("About")); my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("Cancel")); my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("OK")); - + # main loop while(1) { my $event = $self->dialog->waitForEvent(); @@ -769,6 +816,7 @@ sub ask_AllowedServices { } if ($widget == $cancelButton) { + exit(); last; }elsif ($widget == $aboutButton) { my $abtdlg = $self->aboutDialog(); @@ -846,9 +894,9 @@ sub set_ports { if (!$disabled || -x "$::prefix/sbin/shorewall") { # $do_pkgs->ensure_files_are_installed([ [ qw(shorewall shorewall) ], [ qw(shorewall-ipv6 shorewall6) ] ], $::isInstall) or return; - my $conf = AdminPanel::Shared::Shorewall::read_(!$disabled); + my $conf = AdminPanel::Shared::Shorewall::read_(); $self->get_zones(\$conf); - my $shorewall = AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf; + my $shorewall = (AdminPanel::Shared::Shorewall::get_config_file('zones', '') && $conf); if (!$shorewall) { print ("unable to read shorewall configuration, skipping installation"); return; @@ -859,17 +907,20 @@ sub set_ports { $shorewall->{log_net_drop} = $log_net_drop; print ($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); - my $action = 'keep'; - # $fake_in->ask_from_({ - # messages => $self->loc->N("Your firewall configuration has been manually edited and contains -#rules that may conflict with the configuration that has just been set up. -#What do you want to do?"), - # title => $self->loc->N("Firewall"), - # icon => 'banner-security', - # }, - # [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { } } ]); - - # AdminPanel::Shared::Shorewall::write($shorewall, $fake_in); + # NOTE: the 2nd param is undef in this case! + if(!AdminPanel::Shared::Shorewall::write_($shorewall)) + { + # user action request + my $action = $self->sh_gui->ask_fromList({ + title => $self->loc->N("Firewall"), + header => $self->loc->N("Your firewall configuration has been manually edited and contains +rules that may conflict with the configuration that has just been set up. +What do you want to do?"), + list => [ "keep", "drop"], + default => "keep", + }); + AdminPanel::Shared::Shorewall::write_($shorewall,$action); + } } } @@ -921,6 +972,21 @@ sub start { $self->set_ports($disabled, $ports, $log_net_drop) or return; + # restart mandi + require services; + services::is_service_running("mandi") and services::restart("mandi"); + + # restarting services if needed + foreach my $service (@$servers) { + if ($service->{restart}) { + services::is_service_running($_) and services::restart($_) foreach split(' ', $service->{restart}); + } + } + + # clearing pending ifw notifications in net_applet + system('killall -s SIGUSR1 net_applet'); + + return ($disabled, $ports); }; sub ask_from_ { -- cgit v1.2.1 From f4dd2e97f73d1c7d0807afba9c941114e0d0e1d1 Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 17:24:33 +0100 Subject: - added pod for write_ - moved user interaction during write procedure to Module::Firewall - sub write_ return 1 on success, 0 on user interaction requested --- lib/AdminPanel/Shared/Shorewall.pm | 64 ++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/lib/AdminPanel/Shared/Shorewall.pm b/lib/AdminPanel/Shared/Shorewall.pm index f043e86d..50a1110a 100644 --- a/lib/AdminPanel/Shared/Shorewall.pm +++ b/lib/AdminPanel/Shared/Shorewall.pm @@ -4,8 +4,10 @@ use lib qw(/usr/lib/libDrakX); # helps perl_checker use detect_devices; use network::network; use AdminPanel::Shared::RunProgram; -use MDK::Common::Func qw(if_ partition); -use MDK::Common::File qw(cat_); +use MDK::Common::Func qw(if_ partition map_each); +use MDK::Common::File qw(cat_ substInFile output_with_perm); +use MDK::Common::Various qw(to_bool); +use MDK::Common::DataStructure qw(is_empty_array_ref); use List::Util qw(any); use List::MoreUtils qw(uniq); use log; @@ -105,7 +107,7 @@ sub read_ { my @policy = get_config_file('policy', $ver); $conf{log_net_drop} = @policy ? (any { $_->[0] eq 'net' && $_->[1] eq 'all' && $_->[2] eq 'DROP' && $_->[3] } @policy) : 1; - + return \%conf; # get_zones has been moved to AdminPanel::Module::Firewall cause it requires @@ -129,8 +131,42 @@ sub ports_by_proto { \%ports_by_proto; } -sub write { - my ($conf, $o_in) = @_; +#============================================================= + +=head2 write_ + +=head3 INPUT + + $conf: HASH, contains the configuration to write + + $action: Str, possible values are "keep" or "drop" + +=head3 OUTPUT + + 0: requires user interaction + 1: everything has been done + +=head3 DESCRIPTION + +This function stores the configuration for shorewall inside +the proper files. + +=head3 NOTES + +if write_ is called without the $action parameter it can return 0 +(i.e. user interaction requested) when the firewall configuration +has been manually changed. + +In that case the developer will have to handle this request by providing +two choices within the domain (keep | drop) and then recall write_ with +the choosen behaviour. + +=cut + +#============================================================= + +sub write_ { + my ($conf, $action) = @_; my $ver = $conf->{version} || ''; my $use_pptp = any { /^ppp/ && cat_("$::prefix/etc/ppp/peers/$_") =~ /pptp/ } @{$conf->{net_zone}}; my $ports_by_proto = ports_by_proto($conf->{ports}); @@ -139,20 +175,14 @@ sub write { my ($include_drakx, $other_rules) = partition { $_ eq "INCLUDE\trules.drakx\n" } grep { !/^(#|SECTION)/ } cat_("$::prefix${shorewall_root}${ver}/rules"); #- warn if the config is already in rules.drakx and additionnal rules are configured if (!is_empty_array_ref($include_drakx) && !is_empty_array_ref($other_rules)) { + if(!defined($action) || AdminPanel::Shared::trim($action) eq "") + { + return 0; # user interaction requested + } my %actions = ( keep => N("Keep custom rules"), drop => N("Drop custom rules"), ); - my $action = 'keep'; - !$o_in || $o_in->ask_from_( - { - messages => N("Your firewall configuration has been manually edited and contains -rules that may conflict with the configuration that has just been set up. -What do you want to do?"), - title => N("Firewall"), - icon => 'banner-security', - }, - [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { $actions{$_[0]} } } ]) or return; #- reset the rules files if the user has chosen to drop modifications undef $include_drakx if $action eq 'drop'; } @@ -161,7 +191,7 @@ What do you want to do?"), my ($zone, $interface) = @_; [ $zone, $interface, 'detect', if_(detect_devices::is_bridge_interface($interface), 'bridge') ]; }; - + set_config_file('zones', $ver, if_($has_loc_zone, [ 'loc', 'ipv' . ($ver || '4') ]), [ 'net', 'ipv' . ($ver || '4') ], @@ -181,6 +211,7 @@ What do you want to do?"), #- make sure the rules.drakx config is read, erasing user modifications set_config_file('rules', $ver, [ 'INCLUDE', 'rules.drakx' ]); } + print "Trying to write to the file "."$::prefix${shorewall_root}${ver}/rules.drakx\n"; output_with_perm("$::prefix${shorewall_root}${ver}/" . 'rules.drakx', 0600, map { join("\t", @$_) . "\n" } ( if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'tcp', '1723' ]), if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'gre' ]), @@ -206,6 +237,7 @@ What do you want to do?"), } else { services::enable('shorewall', $::isInstall); } + return 1; } sub set_redirected_ports { -- cgit v1.2.1 From 6525f2ec4019ffad75c25164075f33f1aaa05e0d Mon Sep 17 00:00:00 2001 From: Matteo Pasotti Date: Thu, 8 Jan 2015 17:26:44 +0100 Subject: - dropped some debug message left behind --- lib/AdminPanel/Shared/Shorewall.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/AdminPanel/Shared/Shorewall.pm b/lib/AdminPanel/Shared/Shorewall.pm index 50a1110a..03b29aaf 100644 --- a/lib/AdminPanel/Shared/Shorewall.pm +++ b/lib/AdminPanel/Shared/Shorewall.pm @@ -211,7 +211,6 @@ sub write_ { #- make sure the rules.drakx config is read, erasing user modifications set_config_file('rules', $ver, [ 'INCLUDE', 'rules.drakx' ]); } - print "Trying to write to the file "."$::prefix${shorewall_root}${ver}/rules.drakx\n"; output_with_perm("$::prefix${shorewall_root}${ver}/" . 'rules.drakx', 0600, map { join("\t", @$_) . "\n" } ( if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'tcp', '1723' ]), if_($use_pptp, [ 'ACCEPT', 'fw', 'loc:10.0.0.138', 'gre' ]), -- cgit v1.2.1