Don't combine incompatible chains

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2011-10-21 11:55:30 -07:00
parent f31f3dc92a
commit d3d9380df5

View File

@ -809,21 +809,40 @@ sub format_rule( $$;$ ) {
$rule; $rule;
} }
#
# Check two rules to determine if the second rule can be merged into the first.
#
sub compatible( $$ ) {
my ( $ref1, $ref2 ) = @_;
my ( $val1, $val2 );
for ( @unique_options ) {
if ( defined( $val1 = $ref1->{$_} ) && defined( $val2 = $ref2->{$_} ) ) {
unless ( $val1 eq $val2 ) {
my @val1 = split ' ', $val1;
my @val2 = split ' ', $val2;
return 0 if @val1 > @val2 || $val1[0] ne $val2[0];
}
}
}
return 1;
}
# #
# Merge two rules - If the target of the merged rule is a chain, a reference to its # Merge two rules - If the target of the merged rule is a chain, a reference to its
# chain table entry is returned. It is the caller's responsibility # chain table entry is returned. It is the caller's responsibility to
# to handle reference counting. If the target is a builtin, '' is # ensure that the rules being merged are compatible.
# returned. #
# It is also the caller's responsibility to handle reference counting.
# If the target is a builtin, '' is returned.
# #
sub merge_rules( $$$ ) { sub merge_rules( $$$ ) {
my ( $tableref, $toref, $fromref ) = @_; my ( $tableref, $toref, $fromref ) = @_;
my $target = $fromref->{target}; my $target = $fromref->{target};
#
# Since the 'to' rule is a jump to a chain containing the 'from' rule, we
# assume that common unique option values are compatible (such as 'tcp' and
# 'tcp ! syn').
#
for my $option ( @unique_options ) { for my $option ( @unique_options ) {
$toref->{$option} = $fromref->{$option} if exists $fromref->{$option}; $toref->{$option} = $fromref->{$option} if exists $fromref->{$option};
} }
@ -2452,13 +2471,16 @@ sub replace_references1( $$ ) {
my $count = 0; my $count = 0;
my $name = $chainref->{name}; my $name = $chainref->{name};
my $target = $ruleref->{target}; my $target = $ruleref->{target};
my $delete = 1;
for my $fromref ( map $tableref->{$_} , keys %{$chainref->{references}} ) { for my $fromref ( map $tableref->{$_} , keys %{$chainref->{references}} ) {
my $rule = 0; my $rule = 0;
my $skipped = 0;
if ( $fromref->{referenced} ) { if ( $fromref->{referenced} ) {
for ( @{$fromref->{rules}} ) { for ( @{$fromref->{rules}} ) {
$rule++; $rule++;
if ( $_->{target} eq $name ) { if ( $_->{target} eq $name ) {
if ( compatible( $_ , $ruleref ) ) {
# #
# The target is the passed chain -- merge the two rules into one # The target is the passed chain -- merge the two rules into one
# #
@ -2469,16 +2491,25 @@ sub replace_references1( $$ ) {
$count++; $count++;
trace( $fromref, 'R', $rule, $_ ) if $debug; trace( $fromref, 'R', $rule, $_ ) if $debug;
} else {
$skipped++;
}
} }
} }
} }
if ( $skipped ) {
$delete = 0;
} else {
delete $tableref->{$target}{references}{$chainref->{name}} if $tableref->{$target}; delete $tableref->{$target}{references}{$chainref->{name}} if $tableref->{$target};
} }
}
progress_message " $count references to chain $chainref->{name} replaced" if $count; progress_message " $count references to chain $chainref->{name} replaced" if $count;
delete_chain $chainref; delete_chain $chainref if $delete;
$count;
} }
# #
@ -2617,8 +2648,8 @@ sub optimize_level4( $$ ) {
# #
# Replace references to this chain with the target and add the matches # Replace references to this chain with the target and add the matches
# #
replace_references1 $chainref, $firstrule; $progress = 1 if replace_references1 $chainref, $firstrule;
$progress = 1;
} }
} }
} }