diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index ac9936077..d7406d102 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -155,6 +155,7 @@ our %EXPORT_TAGS = ( do_ipsec log_rule expand_rule + promote_blacklist_rules addnatjump set_chain_variables mark_firewall_not_started @@ -213,7 +214,7 @@ our $VERSION = '4.4_13'; # ] # logchains => { = , ... } # references => { => , => , ... } -# frozen => +# blacklist => # } , # => ... # } @@ -621,7 +622,7 @@ sub insert_rule1($$$) $rule = join( ' ', '-A', $rule ); if ( $number < 0 ) { - $chainref->{frozen}++; + $chainref->{blacklist}++; $number = 0; } @@ -642,13 +643,13 @@ sub insert_rule($$$) { # # Do final work to 'delete' a chain. We leave it in the chain table but clear -# the 'referenced', 'rules', 'references' and 'frozen' members. +# the 'referenced', 'rules', 'references' and 'blacklist' members. # sub delete_chain( $ ) { my $chainref = shift; $chainref->{referenced} = 0; - $chainref->{frozen} = 0; + $chainref->{blacklist} = 0; $chainref->{rules} = []; $chainref->{references} = {}; trace( $chainref, 'X', undef, '' ) if $debug; @@ -691,18 +692,18 @@ sub increment_reference_count( $$ ) { # # The rules generated by interface options are added to the interfaces's input chain and # forward chain. Shorewall::Rules::generate_matrix() may decide to move those rules to -# the head of a rules chain (behind any frozen rules already there). +# the head of a rules chain (behind any blacklist rules already there). sub move_rules( $$ ) { my ($chain1, $chain2 ) = @_; if ( $chain1->{referenced} ) { - my $name1 = $chain1->{name}; - my $name2 = $chain2->{name}; - my $rules = $chain2->{rules}; - my $count = @{$chain1->{rules}}; - my $tableref = $chain_table{$chain1->{table}}; - my $frozen = $chain2->{frozen}; + my $name1 = $chain1->{name}; + my $name2 = $chain2->{name}; + my $rules = $chain2->{rules}; + my $count = @{$chain1->{rules}}; + my $tableref = $chain_table{$chain1->{table}}; + my $blacklist = $chain2->{blacklist}; # # We allow '+' in chain names and '+' is an RE meta-character. Escape it. # @@ -713,15 +714,15 @@ sub move_rules( $$ ) { } if ( $debug ) { - my $rule = $frozen; + my $rule = $blacklist; trace( $chain2, 'A', ++$rule, $_ ) for @{$chain1->{rules}}; } - splice @$rules, $frozen, 0, @{$chain1->{rules}}; + splice @$rules, $blacklist, 0, @{$chain1->{rules}}; $chain2->{referenced} = 1; - unless ( $chain2->{frozen} += $chain1->{frozen} ) { + unless ( $chain2->{blacklist} += $chain1->{blacklist} ) { # # In a firewall->x policy chain, multiple DHCP ACCEPT rules can be moved to the head of the chain. # This hack avoids that. @@ -742,15 +743,15 @@ sub move_rules( $$ ) { sub copy_rules( $$ ) { my ($chain1, $chain2 ) = @_; - my $name1 = $chain1->{name}; - my $name = $name1; - my $name2 = $chain2->{name}; - my $frozen1 = $chain1->{frozen}; - my $frozen2 = $chain2->{frozen}; - my @rules1 = @{$chain1->{rules}}; - my $rules2 = $chain2->{rules}; - my $count = @{$chain1->{rules}}; - my $tableref = $chain_table{$chain1->{table}}; + my $name1 = $chain1->{name}; + my $name = $name1; + my $name2 = $chain2->{name}; + my $blacklist1 = $chain1->{blacklist}; + my $blacklist2 = $chain2->{blacklist}; + my @rules1 = @{$chain1->{rules}}; + my $rules2 = $chain2->{rules}; + my $count = @{$chain1->{rules}}; + my $tableref = $chain_table{$chain1->{table}}; # # We allow '+' in chain names and '+' is an RE meta-character. Escape it. # @@ -765,15 +766,15 @@ sub copy_rules( $$ ) { increment_reference_count( $tableref->{$1}, $name2 ) if / -[jg] ([^\s]+)/; } - if ( $frozen1 ) { + if ( $blacklist1 ) { if ( $debug ) { my $rule = @$rules2; trace( $chain2, 'A', ++$rule, $_ ) for @rules1; } - splice @$rules2, $frozen2, 0, splice( @rules1, 0, $frozen1 ); + splice @$rules2, $blacklist2, 0, splice( @rules1, 0, $blacklist1 ); - $chain2->{frozen} += $frozen1; + $chain2->{blacklist} += $blacklist1; } if ( $debug ) { @@ -1021,7 +1022,7 @@ sub new_chain($$) log => 1, cmdlevel => 0, references => {}, - frozen => 0 }; + blacklist => 0 }; trace( $chainref, 'N', undef, '' ) if $debug; @@ -3678,6 +3679,54 @@ sub expand_rule( $$$$$$$$$$;$ ) $diface; } +# +# Where a zone sharing a multi-zone interface has an 'in' blacklist rule, move the rule to the beginning of +# the associated interface chain +# +sub promote_blacklist_rules() { + for my $chain1ref ( grep $_->{blacklist} , values %$filter_table ) { + my $copied = 0; + my $rule = $chain1ref->{rules}[0]; + # + # Isolate the name of the blacklist chain + # + $rule =~ / -j ([^\/s]+)/; + + my $chainb = $1; + + assert( $chainb && $chainb =~ /^black/ ); + + unless ( $chainb eq 'blackout' ) { + # + # An 'in' blacklist rule + # + for my $chain2ref ( map $filter_table->{$_}, keys %{$chain1ref->{references}} ) { + unless ( $chain2ref->{builtin} ) { + # + # This is not INPUT or FORWARD -- we wouldn't want to move the + # rule to the head of one of those chains + # + $copied++; + # + # Copy the blacklist rule to the head of the parent chain unless it + # already has a blacklist rule. + # + unless ( $chain2ref->{blacklist} ) { + unshift @{$chain2ref->{rules}}, $rule; + $chain2ref->{references}{$chainb}++; + $chain2ref->{blacklist}++; + } + } + } + + if ( $copied ) { + shift @{$chain1ref->{rules}}; + $chain1ref->{blacklist} = 0; + $chain1ref->{references}{chainb}--; + } + } + } +} # # The following code generates the input to iptables-restore from the contents of the # @rules arrays in the chain table entries.