aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ManaTools/Module/Firewall.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ManaTools/Module/Firewall.pm')
-rw-r--r--lib/ManaTools/Module/Firewall.pm1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/lib/ManaTools/Module/Firewall.pm b/lib/ManaTools/Module/Firewall.pm
new file mode 100644
index 0000000..2ac56a5
--- /dev/null
+++ b/lib/ManaTools/Module/Firewall.pm
@@ -0,0 +1,1208 @@
+# vim: set et ts=4 sw=4:
+#*****************************************************************************
+#
+# Copyright (c) 2013-2015 Matteo Pasotti <matteo.pasotti@gmail.com>
+#
+# 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 ManaTools::Module::Firewall;
+
+use Modern::Perl '2011';
+use autodie;
+use Moose;
+use Moose::Autobox;
+use utf8;
+
+use yui;
+use ManaTools::Shared qw(trim);
+use ManaTools::Shared::GUI;
+use ManaTools::Shared::Firewall;
+use ManaTools::Shared::Shorewall;
+use ManaTools::Shared::Services;
+
+use MDK::Common::Func qw(if_ partition);
+use MDK::Common::System qw(getVarsFromSh);
+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);
+
+extends qw( ManaTools::Module );
+
+has '+icon' => (
+ default => "/usr/share/icons/manawall.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',
+);
+
+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,
+ isa => 'HashRef',
+ builder => '_initNet',
+);
+
+has 'unlisted' => (
+ is => 'rw',
+ init_arg => undef,
+ isa => 'ArrayRef',
+ builder => '_initUnlisted',
+);
+
+has 'log_net_drop' => (
+ is => 'rw',
+ isa => 'Bool',
+ default => sub { return 1; }
+);
+
+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 &lt;matteo.pasotti\@gmail.com&gt;"
+ };
+}
+
+sub _localeInitialize {
+ my $self = shift();
+
+ # TODO fix domain binding for translation
+ $self->loc(ManaTools::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(ManaTools::Shared::GUI->new() );
+}
+
+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(),
+ hide => 1,
+ prepare => sub { network::nfs::write_nfs_ports(network::nfs::read_nfs_ports()) },
+ 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',
+ hide => 1,
+ },
+ );
+ 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 = {};
+ network::network::read_net_conf($net);
+ return $net;
+}
+
+sub _initUnlisted {
+ my $self = shift();
+ my @unlisted = ();
+ return \@unlisted;
+}
+
+#=============================================================
+
+sub check_ports_syntax {
+ my ($ports) = @_;
+ foreach (split ' ', $ports) {
+ my ($nb, $range, $nb2) = m!^(\d+)(:(\d+))?/(tcp|udp|icmp)$! or return $_;
+ foreach my $port ($nb, if_($range, $nb2)) {
+ 1 <= $port && $port <= 65535 or return $_;
+ }
+ $nb < $nb2 or return $_ if $range;
+ }
+ return '';
+}
+
+#=============================================================
+
+=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) = @_;
+ for my $service(@{$self->all_servers()})
+ {
+ if(any { $port eq $_ } split(' ', $service->{ports}))
+ {
+ return $service;
+ }
+ }
+ return 0;
+}
+
+#=============================================================
+
+=head2 to_ports
+
+=head3 INPUT
+
+ $self: this object
+
+=head3 DESCRIPTION
+
+ This method converts from server definitions to port definitions
+
+=cut
+
+#=============================================================
+
+sub to_ports {
+ my ($self, $servers) = @_;
+ my $ports = join(' ', (map { $_->{ports} } @$servers), @{$self->unlisted()});
+ return $ports;
+}
+
+#=============================================================
+
+=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;
+ foreach (split ' ', $ports) {
+ if (my $s = $self->port2server($_)) {
+ push @l, $s;
+ } else {
+ push (@{$self->unlisted()}, $_);
+ }
+ }
+ my @result = [ uniq(@l) ], join(' ', @{$self->unlisted()});
+ return \@result;
+}
+
+#=============================================================
+
+=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;
+ my $conf = ManaTools::Shared::Shorewall::read_();
+ my $shorewall = (ManaTools::Shared::Shorewall::get_config_file('zones', '') && $conf);
+
+ if ($o_ports) {
+ return ($disabled, $self->from_ports($o_ports));
+ } elsif ($shorewall) {
+ # 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, '');
+ }
+}
+
+sub set_ifw {
+ # my ($do_pkgs, $enabled, $rules, $ports) = @_;
+ my $self = shift();
+ my ($enabled, $rules, $ports) = @_;
+ if ($enabled)
+ {
+ my $ports_by_proto = ManaTools::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";
+ ManaTools::Shared::Shorewall::set_in_file('start', $enabled, "INCLUDE /etc/ifw/start", "INCLUDE /etc/ifw/rules", "iptables -I INPUT 1 -j Ifw");
+ ManaTools::Shared::Shorewall::set_in_file('stop', $enabled, "iptables -D INPUT -j Ifw", "INCLUDE /etc/ifw/stop");
+}
+
+#=============================================================
+
+=head2 choose_watched_services
+
+=head3 INPUT
+
+ $self: this object
+
+ $servers: array of hashes representing servers
+
+=head3 DESCRIPTION
+
+ This method shows the main dialog to let users choose the allowed services
+
+=cut
+
+#=============================================================
+
+sub choose_watched_services {
+ my ($self, $servers) = @_;
+
+ my @l = (@{$self->ifw_rules()}, @$servers, map { { ports => $_ } } @{$self->unlisted()});
+
+ my $enabled = 1;
+ $_->{ifw} = 1 foreach @l;
+
+ my $retval = $self->ask_WatchedServices({
+ title => $self->loc->N("Interactive Firewall"),
+ icon => $self->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."),
+ },
+ [
+ {
+ id=>'useifw',
+ text => $self->loc->N("Use Interactive Firewall"),
+ val => $enabled,
+ type => 'bool'
+ },
+ map {
+ {
+ text => (exists $_->{name} ? $_->{name} : $_->{ports}),
+ val => $_->{ifw},
+ type => 'bool',
+ id => $_->{id},
+ },
+ } @l,
+ ]);
+
+ return if($retval == 0);
+
+ for my $server(@{$self->wdg_ifw()})
+ {
+ for my $k(keys @l)
+ {
+ if(defined($l[$k]->{id}) && defined($server->{id}))
+ {
+ if($server->{id} eq 'useifw')
+ {
+ $enabled = $server->{value};
+ }
+ else
+ {
+ if($l[$k]->{id} eq $server->{id})
+ {
+ $l[$k]->{ifw} = $server->{value};
+ last;
+ }
+ }
+ }
+ }
+ }
+
+ my ($rules, $ports) = partition { exists $_->{ifw_rule} } grep { $_->{ifw} } @l;
+ $self->set_ifw($enabled, [ map { $_->{ifw_rule} } @$rules ], $self->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"));
+
+ my $retval = 0;
+
+ # 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_ifw()})
+ {
+ if($widget == ${$server->{widget}})
+ {
+ if($server->{id} eq 'useifw')
+ {
+ if(!${$server->{widget}}->value())
+ {
+ yui::YUI::ui()->blockEvents();
+ foreach my $server(@{$self->wdg_ifw()})
+ {
+ if($server->{id} ne 'useifw')
+ {
+ ${$server->{widget}}->setValue(0);
+ $server->{value} = ${$server->{widget}}->value();
+ }
+ }
+ yui::YUI::ui()->unblockEvents();
+ last;
+ }
+ }
+ else
+ {
+ $server->{value} = ${$server->{widget}}->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) {
+ $retval = 1;
+ last;
+ }
+ }
+ }
+
+ $self->dialog->destroy();
+
+ #restore old application title
+ yui::YUI::app()->setApplicationTitle($old_title);
+
+ return $retval;
+}
+
+
+#=============================================================
+
+=head2 choose_allowed_services
+
+=head3 INPUT
+
+ $self: this object
+
+ $disabled: boolean
+
+ $servers: array of hashes representing servers
+
+=head3 DESCRIPTION
+
+ This method shows the main dialog to let users choose the allowed services
+
+=cut
+
+#=============================================================
+
+sub choose_allowed_services {
+ my ($self, $disabled, $servers) = @_;
+
+ $_->{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 => $self->icon(),
+ # if_(!$::isEmbedded, banner_title => $self->loc->N("Firewall")),
+ banner_title => $self->loc->N("Firewall"),
+ };
+
+ 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 <b>%s</b>", $self->net()->{PROFILE}) }),
+ { text => $self->loc->N("Everything (no firewall)"), val => \$disabled, type => 'bool' },
+ (map { { text => $_->{name}, val => \$_->{on}, type => 'bool', disabled => sub { $disabled }, id => $_->{id} } } @l),
+ ];
+
+ return if(!$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;
+ }
+ }
+ else
+ {
+ # fake server, the checkbox allowing the user to disable the firewall
+ # if Everything checkbox is selected, value = 1 then firewall disabled = 1
+ $disabled = ${$server->{value}};
+ last;
+ }
+ }
+ }
+
+ return ($disabled, [ grep { $_->{on} } @l ]);
+}
+
+#=============================================================
+
+sub ask_AllowedServices {
+ 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->{title});
+ $logoImage->setWeight($yui::YD_HORIZ,0);
+ $labelAppDescription->setWeight($yui::YD_HORIZ,3);
+
+ my $hbox_content = $factory->createHBox($layout);
+
+ my $widgetContainer = $factory->createVBox($hbox_content);
+
+ my $evry = undef;
+
+ 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);
+ if(!defined($item->{id}))
+ {
+ $evry = $ckbox;
+ }
+ if(defined($item->{disabled}))
+ {
+ $ckbox->setEnabled(!$item->{disabled}->());
+ }
+ 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));
+ my $advButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("A&dvanced"));
+ 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"));
+
+ my $retval = 0;
+
+ # 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 firewall rules");
+ $self->sh_gui->AboutDialog($abtdlg);
+ }elsif ($widget == $okButton) {
+ $retval = 1;
+ last;
+ }
+ elsif ($widget == $advButton) {
+ $self->ask_CustomPorts();
+ }
+ elsif ($widget == $evry) {
+ foreach my $wdg_ckbox(@{$self->wdg_servers()})
+ {
+ if(defined($wdg_ckbox->{id}))
+ {
+ ${$wdg_ckbox->{widget}}->setEnabled(!${$wdg_ckbox->{widget}}->isEnabled());
+ }
+ }
+ }
+ }
+ }
+
+ $self->dialog->destroy();
+
+ #restore old application title
+ yui::YUI::app()->setApplicationTitle($old_title);
+
+ return $retval;
+}
+
+sub ask_CustomPorts {
+ my $self = shift();
+
+ my $adv_msg = $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.");
+
+ my $old_title = yui::YUI::app()->applicationTitle();
+ my $win_title = $self->loc->N("Define miscellaneus ports");
+
+ ## set new title to get it in dialog
+ yui::YUI::app()->setApplicationTitle($win_title);
+
+ my $factory = yui::YUI::widgetFactory;
+ my $optional = yui::YUI::optionalWidgetFactory;
+
+ my $advdlg = $factory->createPopupDialog();
+ my $layout = $factory->createVBox($advdlg);
+
+ my $hbox_header = $factory->createHBox($layout);
+ my $headLeft = $factory->createHBox($factory->createLeft($hbox_header));
+ my $headRight = $factory->createHBox($factory->createRight($hbox_header));
+
+ my $labelAppDescription = $factory->createLabel($headRight,$self->loc->N("Other ports"));
+ $labelAppDescription->setWeight($yui::YD_HORIZ,3);
+
+ my $hbox_content = $factory->createHBox($layout);
+ my $vbox_inputs = $factory->createVBox($hbox_content);
+ my $labelAdvMessage = $factory->createLabel($factory->createHBox($vbox_inputs), $adv_msg);
+ my $txtPortsList = $factory->createInputField($vbox_inputs,'');
+ $txtPortsList->setValue(join(' ',@{$self->unlisted()}));
+ my $ckbLogFWMessages = $factory->createCheckBox($factory->createHBox($vbox_inputs), $self->loc->N("Log firewall messages in system logs"), $self->log_net_drop());
+ 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 $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel"));
+ my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&OK"));
+
+ my $retval = 0;
+
+ # main loop
+ while(1) {
+ my $event = $advdlg->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 )
+ {
+ $retval = 0;
+ last;
+ }
+ elsif( $widget == $okButton )
+ {
+ if(scalar(@{$self->unlisted()}) > 0)
+ {
+ $self->unlisted([]);
+ }
+ my $invalid_ports = check_ports_syntax($txtPortsList->value());
+ if(ManaTools::Shared::trim($invalid_ports) eq '')
+ {
+ if($txtPortsList->value() =~m/\s+/g)
+ {
+ my @unlstd = split(' ', $txtPortsList->value());
+ foreach my $p(@unlstd)
+ {
+ push(@{$self->unlisted()},$p);
+ }
+ }
+ else
+ {
+ if(ManaTools::Shared::trim($txtPortsList->value()) ne '')
+ {
+ push(@{$self->unlisted()}, ManaTools::Shared::trim($txtPortsList->value()));
+ }
+ }
+ $retval = 1;
+ }
+ else
+ {
+ $self->sh_gui->warningMsgBox({
+ title=>$self->loc->N("Invalid port given"),
+ text=> $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_ports)
+ });
+ $retval = 0;
+ }
+ last;
+ }
+ }
+ }
+
+ $advdlg->destroy();
+
+ #restore old application title
+ yui::YUI::app()->setApplicationTitle($old_title);
+
+ return $retval;
+}
+
+sub get_zones {
+ my $self = shift();
+ my $confref = shift();
+ my $disabled = shift();
+ my $conf = ${$confref};
+ my $interfacesfile = ManaTools::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 ManaTools::Shared::Shorewall::get_net_zone_interfaces($interfacesfile, $self->net(), \@all_intf);
+
+ # if firewall/shorewall is not disabled (i.e. everything has been allowed)
+ # then ask for network interfaces to protect
+ if(!$disabled)
+ {
+ 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 {
+ {
+ id => $_,
+ text => network::tools::get_interface_description($self->net(), $_),
+ val => \$net_zone{$_},
+ type => 'bool'
+ };
+ } (sort keys %net_zone) ]
+ });
+
+ if(!defined($retvals))
+ {
+ return 0;
+ }
+ else
+ {
+ # it was: ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone;
+ foreach my $net_int (@{$retvals})
+ {
+ push (@{$conf->{net_zone}}, $net_int);
+ }
+ return $retvals;
+ }
+ }
+
+ foreach my $net_int(keys %net_zone)
+ {
+ push (@{$conf->{net_zone}}, $net_int);
+ }
+ return keys %net_zone;
+}
+
+#=============================================================
+
+=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 ($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 $conf = ManaTools::Shared::Shorewall::read_();
+ if(!$self->get_zones(\$conf,$disabled))
+ {
+ # Cancel button has been pressed, aborting
+ return 0;
+ }
+ my $shorewall = (ManaTools::Shared::Shorewall::get_config_file('zones', '') && $conf);
+ if (!$shorewall) {
+ print ("unable to read shorewall configuration, skipping installation");
+ return 0;
+ }
+
+ $shorewall->{disabled} = $disabled;
+ $shorewall->{ports} = $ports;
+ $shorewall->{log_net_drop} = $log_net_drop;
+
+ print ($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports");
+
+ # NOTE: the 2nd param is undef in this case!
+ if(!ManaTools::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",
+ });
+ ManaTools::Shared::Shorewall::write_($shorewall,$action);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#=============================================================
+
+=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, $log_net_drop) = $self->get_conf(undef) or return;
+
+ # $log_net_drop: network::shorewall log_net_drop attribute
+ $self->log_net_drop($log_net_drop);
+ undef($log_net_drop);
+ ($disabled, $servers) = $self->choose_allowed_services($disabled, @$servers) 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) or return;
+ }
+
+ # preparing services when required ( look at $self->all_servers() )
+ foreach (@$servers) {
+ exists $_->{prepare} and $_->{prepare}();
+ }
+
+ my $ports = $self->to_ports($servers);
+
+ $self->set_ports($disabled, $ports, $self->log_net_drop()) or return;
+
+ # restart mandi
+ my $services = ManaTools::Shared::Services->new();
+ $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);
+};
+
+1;