From 2a2a7530c238019b35aa4de418cfe19579449805 Mon Sep 17 00:00:00 2001 From: teastep <teastep@fbd18981-670d-0410-9b5c-8dc0c1a9a2bb> Date: Wed, 30 Jan 2008 00:03:25 +0000 Subject: [PATCH] Add optimizations in basic chain handling git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8122 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall-perl/Shorewall/Chains.pm | 116 +++++++++++++++++++++++++++++ Shorewall-perl/Shorewall/Rules.pm | 76 ++++++++++--------- Shorewall-perl/Shorewall/Zones.pm | 4 + 3 files changed, 162 insertions(+), 34 deletions(-) diff --git a/Shorewall-perl/Shorewall/Chains.pm b/Shorewall-perl/Shorewall/Chains.pm index 6f56f418f..bec02d3f4 100644 --- a/Shorewall-perl/Shorewall/Chains.pm +++ b/Shorewall-perl/Shorewall/Chains.pm @@ -76,10 +76,16 @@ our %EXPORT_TAGS = ( chain_base forward_chain zone_forward_chain + use_interface_forward_chain + interface_forward_chain input_chain zone_input_chain + use_interface_input_chain + interface_input_chain output_chain zone_output_chain + use_output_chain + interface_output_chain masq_chain syn_flood_chain mac_chain @@ -520,6 +526,32 @@ sub zone_forward_chain($) { chain_base($_[0]) . '_frwd'; } +# +# Returns true if we're to use the interface's forward chain +# +sub use_interface_forward_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{forward_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + $interfaceref->{nets} != 1 || $chainref->{referenced}; +} + +# +# Returns a reference to the forward chain for an interface +# +sub interface_forward_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{forward_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + $interfaceref->{nets} != 1 || $chainref->{referenced} ? $chainref : $filter_table->{zone_forward_chain $interfaceref->{zone}}; +} + # # Input Chain for an interface # @@ -535,6 +567,48 @@ sub zone_input_chain($) { chain_base($_[0]) . '_input'; } +# +# Returns true if we're to use the interface's input chain +# +sub use_interface_input_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{input_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + return 1 if $interfaceref->{nets} != 1 || $chainref->{referenced}; + + my $chainref1 = $filter_table->{zone_input_chain $interfaceref->{zone}}; + + return 1 if $chainref1; + + $chainref1 = $filter_table->{join( '' , $interfaceref->{zone} , '2' , firewall_zone )}; + + ! $chainref1->{referenced}; +} + +# +# Returns a reference to the input chain for the passed interface +# +sub interface_input_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{input_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + return $chainref if $interfaceref->{nets} != 1 || $chainref->{referenced}; + + my $chainref1 = $filter_table->{zone_input_chain $interfaceref->{zone}}; + + return $chainref1 if $chainref1; + + $chainref1 = $filter_table->{join( '', $interfaceref->{zone} , '2', firewall_zone )}; + + $chainref1->{referenced} ? $chainref1 : $chainref; +} + # # Output Chain for an interface # @@ -551,6 +625,48 @@ sub zone_output_chain($) { } # +# Returns true if we're to use the interface's output chain +# +sub use_output_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{output_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + return 1 if $interfaceref->{nets} != 1 || $chainref->{referenced}; + + my $chainref1 = $filter_table->{zone_output_chain $interfaceref->{zone}}; + + return 1 if $chainref1; + + $chainref1 = $filter_table->{join( '', firewall_zone , '2', $interfaceref->{zone} )}; + + ! $chainref1->{referenced}; +} + +# +# Returns a reference to the output chain for a zone +# +sub interface_output_chain($) { + my $interface = $_[0]; + my $chainref = $filter_table->{output_chain($interface)}; + my $interfaceref = find_interface($interface); + # + # We must use the interfaces's chain if it is referenced (has rules in it) or if the interface is associated with multiple zone nets + # + return $chainref if $interfaceref->{nets} != 1 || $chainref->{referenced}; + + my $chainref1 = $filter_table->{zone_output_chain $interfaceref->{zone}}; + + return $chainref1 if $chainref1; + + $chainref1 = $filter_table->{join( '', firewall_zone , '2', $interfaceref->{zone} )}; + + $chainref1->{referenced} ? $chainref1 : $chainref; +} + +## # Masquerade Chain for an interface # sub masq_chain($) diff --git a/Shorewall-perl/Shorewall/Rules.pm b/Shorewall-perl/Shorewall/Rules.pm index 2269ab361..e2938efa8 100644 --- a/Shorewall-perl/Shorewall/Rules.pm +++ b/Shorewall-perl/Shorewall/Rules.pm @@ -503,8 +503,8 @@ sub add_common_rules() { add_rule_pair new_standard_chain( 'logreject' ), ' ' , 'reject' , $level ; for $interface ( all_interfaces ) { - new_standard_chain( $_ ) for first_chains( $interface ); - new_standard_chain output_chain( $interface ); + ensure_chain( 'filter', $_ ) for first_chains( $interface ); + ensure_chain( 'filter', output_chain( $interface ) ); } run_user_exit1 'initdone'; @@ -1534,14 +1534,16 @@ sub generate_matrix() { } for my $interface ( keys %$source_ref ) { - my $arrayref = $source_ref->{$interface}; - for my $hostref ( @{$arrayref} ) { - my $ipsec_match = match_ipsec_in $zone , $hostref; - for my $net ( @{$hostref->{hosts}} ) { - add_rule( - $filter_table->{forward_chain $interface} , - join( '', match_source_net( $net ), $ipsec_match, "-j $frwd_ref->{name}" ) - ); + if ( use_interface_forward_chain( $interface ) ) { + my $arrayref = $source_ref->{$interface}; + for my $hostref ( @{$arrayref} ) { + my $ipsec_match = match_ipsec_in $zone , $hostref; + for my $net ( @{$hostref->{hosts}} ) { + add_rule( + $filter_table->{forward_chain $interface} , + join( '', match_source_net( $net ), $ipsec_match, "-j $frwd_ref->{name}" ) + ); + } } } } @@ -1621,20 +1623,22 @@ sub generate_matrix() { if ( $chain1 ) { my $nextchain; - my $outputref = $filter_table->{output_chain $interface}; + my $outputref = interface_output_chain $interface; - if ( @$exclusions ) { - my $output = zone_output_chain $zone; - add_rule $outputref , join( '', $dest, $ipsec_out_match, "-j $output" ); - add_rule $filter_table->{$output} , "-j $chain1"; - $nextchain = $output; - } else { - add_rule $outputref , join( '', $dest, $ipsec_out_match, "-j $chain1" ); - $nextchain = $chain1; + if ( use_output_chain $interface ) { + if ( @$exclusions ) { + my $output = zone_output_chain $zone; + add_rule $outputref , join( '', $dest, $ipsec_out_match, "-j $output" ); + add_rule $filter_table->{$output} , "-j $chain1"; + $nextchain = $output; + } else { + add_rule $outputref , join( '', $dest, $ipsec_out_match, "-j $chain1" ); + $nextchain = $chain1; + } + + add_rule( $outputref , join('', '-d 255.255.255.255 ' , $ipsec_out_match, "-j $nextchain" ) ) + if $hostref->{options}{broadcast}; } - - add_rule( $outputref , join('', match_source_net $net, '-d 255.255.255.255 ' . $ipsec_out_match, "-j $nextchain" ) ) - if $hostref->{options}{broadcast}; } next if $hostref->{options}{destonly}; @@ -1654,18 +1658,22 @@ sub generate_matrix() { # add_rule $preroutingref, join( '', match_source_dev( $interface), $source, $ipsec_in_match, '-j RETURN' ) if $nested; - if ( $chain2 ) { - if ( @$exclusions ) { - my $input = zone_input_chain $zone; - add_rule $filter_table->{input_chain $interface}, join( '', $source, $ipsec_in_match, "-j $input" ); - add_rule $filter_table->{ $input } , "-j $chain2"; - } else { - add_rule $filter_table->{input_chain $interface}, join( '', $source, $ipsec_in_match, "-j $chain2" ); + if ( use_interface_input_chain $interface ) { + if ( $chain2 ) { + if ( @$exclusions ) { + my $input = zone_input_chain $zone; + add_rule $filter_table->{input_chain $interface}, join( '', $source, $ipsec_in_match, "-j $input" ); + add_rule $filter_table->{ $input } , "-j $chain2"; + } else { + add_rule $filter_table->{input_chain $interface}, join( '', $source, $ipsec_in_match, "-j $chain2" ); + } } } - add_rule $filter_table->{forward_chain $interface} , join( '', $source, $ipsec_in_match. "-j $frwd_ref->{name}" ) - if $hostref->{ipsec} ne 'ipsec'; + if ( use_interface_forward_chain $interface ) { + add_rule $filter_table->{forward_chain $interface} , join( '', $source, $ipsec_in_match. "-j $frwd_ref->{name}" ) + if $hostref->{ipsec} ne 'ipsec'; + } } } } @@ -1831,9 +1839,9 @@ sub generate_matrix() { # Now add the jumps to the interface chains from FORWARD, INPUT, OUTPUT and POSTROUTING # for my $interface ( @interfaces ) { - add_rule $filter_table->{FORWARD} , match_source_dev( $interface ) . "-j " . forward_chain $interface; - add_rule $filter_table->{INPUT} , match_source_dev( $interface ) . "-j " . input_chain $interface; - add_rule $filter_table->{OUTPUT} , "-o $interface -j " . output_chain $interface unless get_interface_option( $interface, 'port' ); + add_rule $filter_table->{FORWARD} , match_source_dev( $interface ) . "-j " . interface_forward_chain($interface)->{name}; + add_rule $filter_table->{INPUT} , match_source_dev( $interface ) . "-j " . interface_input_chain($interface)->{name}; + add_rule $filter_table->{OUTPUT} , "-o $interface -j " . interface_output_chain($interface)->{name} unless get_interface_option( $interface, 'port' ); addnatjump 'POSTROUTING' , masq_chain( $interface ) , match_dest_dev( $interface ); } diff --git a/Shorewall-perl/Shorewall/Zones.pm b/Shorewall-perl/Shorewall/Zones.pm index b7f178ae3..27daa8f0a 100644 --- a/Shorewall-perl/Shorewall/Zones.pm +++ b/Shorewall-perl/Shorewall/Zones.pm @@ -125,6 +125,7 @@ our %reservedName = ( all => 1, # ... # } # zone => <zone name> +# nets => <number of nets in interface/hosts records referring to this interface> # bridge => <bridge> # broadcasts => 'none', 'detect' or [ <addr1>, <addr2>, ... ] # } @@ -461,6 +462,8 @@ sub add_group_to_zone($$$$$) $ifacezone = '' unless defined $ifacezone; for my $host ( @$networks ) { + $interfaces{$interface}{nets}++; + fatal_error "Invalid Host List" unless defined $host and $host ne ''; if ( substr( $host, 0, 1 ) eq '!' ) { @@ -636,6 +639,7 @@ sub validate_interfaces_file( $ ) } $interfaces{$interface}{name} = $interface; + $interfaces{$interface}{nets} = 0; my $wildcard = 0;