diff options
Diffstat (limited to 'lib/ManaTools/Module/Firewall.pm')
-rw-r--r-- | lib/ManaTools/Module/Firewall.pm | 1208 |
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 00000000..2ac56a59 --- /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 <matteo.pasotti\@gmail.com>" + }; +} + +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; |