aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatteo Pasotti <matteo.pasotti@gmail.com>2015-01-08 17:29:54 +0100
committerMatteo Pasotti <matteo.pasotti@gmail.com>2015-01-08 17:29:54 +0100
commitab9bc693f8e8b31792eff493d860e9bb4d072cbf (patch)
tree1417543ee00cb1da6996982439af3b719e81f3ca
parentc3bfd51e5d52af523d039f8612be0058b01f9335 (diff)
parent6525f2ec4019ffad75c25164075f33f1aaa05e0d (diff)
downloadcolin-keep-ab9bc693f8e8b31792eff493d860e9bb4d072cbf.tar
colin-keep-ab9bc693f8e8b31792eff493d860e9bb4d072cbf.tar.gz
colin-keep-ab9bc693f8e8b31792eff493d860e9bb4d072cbf.tar.bz2
colin-keep-ab9bc693f8e8b31792eff493d860e9bb4d072cbf.tar.xz
colin-keep-ab9bc693f8e8b31792eff493d860e9bb4d072cbf.zip
Merge branch 'manawall'
-rw-r--r--MANIFEST4
-rw-r--r--Makefile.PL3
-rw-r--r--lib/AdminPanel/Module/Firewall.pm1054
-rw-r--r--lib/AdminPanel/Shared/Firewall.pm35
-rw-r--r--lib/AdminPanel/Shared/GUI.pm180
-rw-r--r--lib/AdminPanel/Shared/Shorewall.pm265
-rwxr-xr-xscripts/manawall36
7 files changed, 1577 insertions, 0 deletions
diff --git a/MANIFEST b/MANIFEST
index 4dd184e..7104420 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
diff --git a/Makefile.PL b/Makefile.PL
index 834e6e0..ebe6ee4 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,
@@ -72,6 +74,7 @@ WriteMakefile(
scripts/manaproxy
scripts/manaservice
scripts/manauser
+ scripts/manawall
modules/contribfinder.py
modules/rpmdragora/dragora-urpm-addmedia
modules/rpmdragora/dragora-urpm-sources.pl
diff --git a/lib/AdminPanel/Module/Firewall.pm b/lib/AdminPanel/Module/Firewall.pm
new file mode 100644
index 0000000..c24c7cd
--- /dev/null
+++ b/lib/AdminPanel/Module/Firewall.pm
@@ -0,0 +1,1054 @@
+# 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 AdminPanel::Module::Firewall;
+
+use Modern::Perl '2011';
+use autodie;
+use Moose;
+use Moose::Autobox;
+use utf8;
+
+use yui;
+use AdminPanel::Shared qw(trim);
+use AdminPanel::Shared::GUI;
+use AdminPanel::Shared::Firewall;
+use AdminPanel::Shared::Shorewall;
+
+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( 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',
+);
+
+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 '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(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 = (
+ {
+ 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;
+}
+
+#=============================================================
+
+=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
+
+ $unlisted: unlisted services
+
+=head3 DESCRIPTION
+
+ This method converts from server definitions to port definitions
+
+=cut
+
+#=============================================================
+
+sub to_ports {
+ my ($self, $servers, $unlisted) = @_;
+ join(' ', (map { $_->{ports} } @$servers), if_($unlisted, $unlisted));
+}
+
+#=============================================================
+
+=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;
+ 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 ($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 = 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
+
+=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 => $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.
+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 },
+ 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;
+
+ $self->set_ifw($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_ifw()})
+ {
+ if($widget == ${$server->{widget}})
+ {
+ ${$server->{value}} = !${$server->{value}};
+ }
+ }
+
+ if ($widget == $cancelButton) {
+ exit();
+ 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
+
+=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 => $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.
+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 <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),
+ { 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);
+
+ 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);
+}
+
+#=============================================================
+
+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);
+
+ 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_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 $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) {
+ exit();
+ 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) {
+ last;
+ }
+ }
+ }
+
+ $self->dialog->destroy();
+
+ #restore old application title
+ yui::YUI::app()->setApplicationTitle($old_title);
+
+ 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
+
+=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 = AdminPanel::Shared::Shorewall::read_();
+ $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;
+ }
+
+ $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(!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);
+ }
+ }
+}
+
+#=============================================================
+
+=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;
+
+ # 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_ {
+ 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;
diff --git a/lib/AdminPanel/Shared/Firewall.pm b/lib/AdminPanel/Shared/Firewall.pm
new file mode 100644
index 0000000..ac44777
--- /dev/null
+++ b/lib/AdminPanel/Shared/Firewall.pm
@@ -0,0 +1,35 @@
+# vim: set et ts=4 sw=4:
+#*****************************************************************************
+#
+# Copyright (c) 2013-2014 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 AdminPanel::Shared::Firewall;
+
+use Moose;
+use diagnostics;
+use utf8;
+
+use lib qw(/usr/lib/libDrakX);
+use network::nfs;
+use network::network;
+use network::tools;
+
+sub _initialize {
+ my $self = shift();
+}
+
+1;
diff --git a/lib/AdminPanel/Shared/GUI.pm b/lib/AdminPanel/Shared/GUI.pm
index ced99c9..e305276 100644
--- a/lib/AdminPanel/Shared/GUI.pm
+++ b/lib/AdminPanel/Shared/GUI.pm
@@ -325,6 +325,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
=head3 INPUT
@@ -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
diff --git a/lib/AdminPanel/Shared/Shorewall.pm b/lib/AdminPanel/Shared/Shorewall.pm
new file mode 100644
index 0000000..03b29aa
--- /dev/null
+++ b/lib/AdminPanel/Shared/Shorewall.pm
@@ -0,0 +1,265 @@
+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 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;
+
+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 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 {
+ 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;
+}
+
+#=============================================================
+
+=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});
+ 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)) {
+ 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"),
+ );
+ #- 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);
+ }
+ return 1;
+}
+
+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;
diff --git a/scripts/manawall b/scripts/manawall
new file mode 100755
index 0000000..30b6480
--- /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 <http://www.gnu.org/licenses/>.
+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;