diff options
Diffstat (limited to 'lib/network/shorewall.pm')
-rw-r--r-- | lib/network/shorewall.pm | 151 |
1 files changed, 92 insertions, 59 deletions
diff --git a/lib/network/shorewall.pm b/lib/network/shorewall.pm index 2567b48..ce90d4e 100644 --- a/lib/network/shorewall.pm +++ b/lib/network/shorewall.pm @@ -1,12 +1,13 @@ package network::shorewall; # $Id$ use detect_devices; -use network::ethernet; use network::network; use run_program; use common; use log; +my $shorewall_root = "/etc/shorewall"; + sub check_iptables() { -f "$::prefix/etc/sysconfig/iptables" || $::isStandalone && do { @@ -26,18 +27,12 @@ sub set_config_file { } else { $_ = '' if /^[^#]/; } - } "$::prefix/etc/shorewall/$file"; + } "$::prefix${shorewall_root}/$file"; } sub get_config_file { my ($file) = @_; - map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix/etc/shorewall/$file"); -} - -sub get_ifcfg_interface() { - my $net = {}; - network::network::read_net_conf($net); - network::tools::get_default_gateway_interface($net); + map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix${shorewall_root}/$file"); } sub dev_to_shorewall { @@ -47,53 +42,47 @@ sub dev_to_shorewall { $dev; } -sub get_shorewall_interface() { +sub get_net_zone_interfaces { + my ($net) = @_; #- read shorewall configuration first - foreach (get_config_file('interfaces')) { - $_->[0] eq 'net' and return $_->[1]; - } + my @interfaces = map { $_->[1] } grep { $_->[0] eq 'net' } get_config_file('interfaces'); #- else try to find the best interface available - dev_to_shorewall(get_ifcfg_interface()); -} - -our $ask_shorewall_interface_label = N_("Please enter the name of the interface connected to the internet. - -Examples: - ppp+ for modem or DSL connections, - eth0, or eth1 for cable connection, - ippp+ for a isdn connection. -"); - -sub shorewall_interface_choices { - my ($refval) = @_; - my $modules_conf = modules::any_conf->read; - my @all_cards = network::ethernet::get_eth_cards($modules_conf); - my %net_devices = network::ethernet::get_eth_cards_names(@all_cards); - put_in_hash(\%net_devices, { 'ppp+' => 'ppp+', 'ippp+' => 'ippp+' }); - - [ { label => N("Net Device"), val => $refval, list => [ sort keys %net_devices ], format => sub { $net_devices{$_[0]} || $_[0] }, not_edit => 0 } ]; + @interfaces ? @interfaces : dev_to_shorewall(network::tools::get_default_gateway_interface($net)); } -sub read_default_interfaces { +sub get_zones { my ($conf, $o_in) = @_; - my $interface = get_shorewall_interface(); - $o_in and $o_in->ask_from('', translate($ask_shorewall_interface_label), shorewall_interface_choices(\$interface)); - set_net_interface($conf, $interface); + my $net = {}; + network::network::read_net_conf($net); + #- find all interfaces but alias interfaces + my @all_intf = grep { !/:/ } uniq(keys(%{$net->{ifcfg}}), detect_devices::get_net_interfaces()); + my %net_zone = map { $_ => undef } @all_intf; + $net_zone{$_} = 1 foreach get_net_zone_interfaces($net); + $o_in and $o_in->ask_from('', 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. + +Which interfaces should be protected? +"), [ + map { + { text => network::tools::get_interface_description($net, $_), val => \$net_zone{$_}, type => 'bool' }; + } (sort keys %net_zone) ]); + ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone; } -sub set_net_interface { +sub add_interface_to_net_zone { my ($conf, $interface) = @_; - $conf->{net_interface} = $interface; - my $net = {}; - network::network::read_net_conf($net); - my @all_intf = uniq((map { dev_to_shorewall($_) } keys %{$net->{ifcfg}}), detect_devices::getNet()); - #- keep all other interfaces (but alias interfaces) in local zone - $conf->{loc_interface} = [ grep { !/:/ && $_ ne $interface } @all_intf ]; + if (!member($interface, @{$conf->{net_zone}})) { + push @{$conf->{net_zone}}, $interface; + @{$conf->{loc_zone}} = grep { $_ ne $interface } @{$conf->{loc_zone}}; + } } sub read { my ($o_in) = @_; - my @rules = get_config_file('rules'); + #- read old rules file if config is not moved to rules.drakx yet + my @rules = get_config_file(-f "$::prefix${shorewall_root}/rules.drakx" ? 'rules.drakx' : 'rules'); my %conf = (disabled => !glob_("$::prefix/etc/rc3.d/S*shorewall"), ports => join(' ', map { my $e = $_; @@ -103,10 +92,14 @@ sub read { $conf{redirects}{$_->[3]}{$_->[2]} = $_->[4] foreach grep { $_->[0] eq 'REDIRECT' } @rules; if (my ($e) = get_config_file('masq')) { - $conf{masq_subnet} = $e->[1]; + ($conf{masq}{net_interface}, $conf{masq}{subnet}) = @$e; } - read_default_interfaces(\%conf, $o_in); - $conf{net_interface} && \%conf; + + my @policy = get_config_file('policy'); + $conf{log_net_drop} = @policy ? (any { $_->[0] eq 'net' && $_->[1] eq 'all' && $_->[2] eq 'DROP' && $_->[3] } @policy) : 1; + + get_zones(\%conf, $o_in); + $conf{net_zone}[0] && \%conf; } sub ports_by_proto { @@ -119,12 +112,44 @@ sub ports_by_proto { \%ports_by_proto; } +sub upgrade_to_shorewall3() { + #- the 'FW' option has been removed from shorewall.conf as of shorewall 3.0 + my $ipsecfile_ok; + substInFile { + undef $_ if /^\s*FW=/; + if ((/^\s*IPSECFILE=/ || eof) && !$ipsecfile_ok) { + $ipsecfile_ok = 1; + $_ = "IPSECFILE=zones\n"; + } + } "$::prefix${shorewall_root}/shorewall.conf"; +} + sub write { - my ($conf) = @_; - my $default_intf = get_ifcfg_interface(); - my $use_pptp = $default_intf =~ /^ppp/ && cat_("$::prefix/etc/ppp/peers/$default_intf") =~ /pptp/; + my ($conf, $o_in) = @_; + my $use_pptp = any { /^ppp/ && cat_("$::prefix/etc/ppp/peers/$_") =~ /pptp/ } @{$conf->{net_zone}}; my $ports_by_proto = ports_by_proto($conf->{ports}); + my ($include_drakx, $other_rules) = partition { $_ eq "INCLUDE\trules.drakx\n" } grep { !/^#/ } cat_("$::prefix${shorewall_root}/rules"); + #- warn if the config is already in rules.drakx and additionnal rules are configured + if (!is_empty_array_ref($include_drakx) && !is_empty_array_ref($other_rules)) { + my %actions = ( + keep => N("Keep custom rules"), + drop => N("Drop custom rules"), + ); + my $action = 'keep'; + !$o_in || $o_in->ask_from_( + { + messages => N("Your firewall configuration has been manually edited and contains +rules that may conflict with the configuration that has just been set up. +What do you want to do?"), + title => N("Firewall"), + icon => 'banner-security', + }, + [ { val => \$action, type => 'list', list => [ 'keep', 'drop' ], format => sub { $actions{$_[0]} } } ]) or return; + #- reset the rules files if the user has chosen to drop modifications + undef $include_drakx if $action eq 'drop'; + } + my $interface_settings = sub { my ($zone, $interface) = @_; [ $zone, $interface, 'detect', if_(detect_devices::is_bridge_interface($interface), 'routeback') ]; @@ -132,28 +157,34 @@ sub write { set_config_file("zones", [ 'net', 'ipv4' ], - if_($conf->{loc_interface}[0], [ 'loc', 'ipv4' ]), + if_($conf->{loc_zone}[0], [ 'loc', 'ipv4' ]), [ 'fw', 'firewall' ], ); set_config_file('interfaces', - $interface_settings->('net', $conf->{net_interface}), - (map { $interface_settings->('loc', $_) } @{$conf->{loc_interface} || []}), + (map { $interface_settings->('net', $_) } @{$conf->{net_zone}}), + (map { $interface_settings->('loc', $_) } @{$conf->{loc_zone} || []}), ); set_config_file('policy', - if_($conf->{loc_interface}[0], [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), + if_($conf->{loc_zone}[0], [ 'loc', 'net', 'ACCEPT' ], [ 'loc', 'fw', 'ACCEPT' ], [ 'fw', 'loc', 'ACCEPT' ]), [ 'fw', 'net', 'ACCEPT' ], - [ 'net', 'all', 'DROP', 'info' ], + [ 'net', 'all', 'DROP', if_($conf->{log_net_drop}, 'info') ], [ 'all', 'all', 'REJECT', 'info' ], ); - set_config_file('rules', + if (is_empty_array_ref($include_drakx)) { + #- make sure the rules.drakx config is read, erasing user modifications + set_config_file('rules', [ 'INCLUDE', 'rules.drakx' ]); + } + output_with_perm("$::prefix${shorewall_root}/" . '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 { map_each { [ 'REDIRECT', 'loc', $::a, $_, $::b, '-' ] } %{$conf->{redirects}{$_}}; } keys %{$conf->{redirects}}), - ); - set_config_file('masq', if_($conf->{masq_subnet}, [ $conf->{net_interface}, $conf->{masq_subnet} ])); + )); + set_config_file('masq', if_(exists $conf->{masq}, [ $conf->{masq}{net_interface}, $conf->{masq}{subnet} ])); + + upgrade_to_shorewall3(); require services; if ($conf->{disabled}) { @@ -164,7 +195,9 @@ sub write { } } -sub update_interfaces_list() { +sub update_interfaces_list { + my ($o_intf) = @_; + $o_intf && member($o_intf, map { $_->[1] } get_config_file('interfaces')) and return; my $shorewall = network::shorewall::read(); $shorewall && !$shorewall->{disabled} and network::shorewall::write($shorewall); } |