From 55045ace4b920ebbcc180808cf88d399c0ae41d5 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Thu, 16 Jul 2009 11:05:37 -0700 Subject: [PATCH] Optimize nonat rules in certain cases --- Shorewall/Perl/Shorewall/Chains.pm | 76 ++++++++++++++++++------------ Shorewall/Perl/Shorewall/Rules.pm | 49 +++++++++++++++---- 2 files changed, 87 insertions(+), 38 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index d210ef670..0137fe680 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -114,6 +114,7 @@ our %EXPORT_TAGS = ( finish_section setup_zone_mss newexclusionchain + newnonatchain source_exclusion dest_exclusion clearrule @@ -242,7 +243,6 @@ use constant { NO_RESTRICT => 0, # FORWARD chain rule - Both -i and POSTROUTE_RESTRICT => 16, # POSTROUTING chain rule - -i converted to -s
using main routing table ALL_RESTRICT => 12 # fw->fw rule - neither -i nor -o allowed }; -our $exclseq; our $iprangematch; our $chainseq; our $idiotcount; @@ -335,11 +335,7 @@ sub initialize( $ ) { # $comment = ''; # - # Used to sequence 'exclusion' chains with names 'excl0', 'excl1', ... - # - $exclseq = 0; - # - # Used to sequence 'log' chains with names 'log0', 'log1', etc. + # Used to sequence chains names. # $chainseq = 0; # @@ -1261,7 +1257,7 @@ sub setup_zone_mss() { } sub newexclusionchain() { - my $seq = $exclseq++; + my $seq = $chainseq++; "excl${seq}"; } @@ -1270,6 +1266,11 @@ sub newlogchain() { "log${seq}"; } +sub newnonatchain() { + my $seq = $chainseq++; + "nonat${seq}"; +} + # # If the passed exclusion array is non-empty then: # @@ -2358,7 +2359,7 @@ sub set_global_variables( $ ) { # # Returns the destination interface specified in the rule, if any. # -sub expand_rule( $$$$$$$$$$ ) +sub expand_rule( $$$$$$$$$$;$ ) { my ($chainref , # Chain $restriction, # Determines what to do with interface names in the SOURCE or DEST @@ -2369,7 +2370,8 @@ sub expand_rule( $$$$$$$$$$ ) $target, # Target ('-j' part of the rule) $loglevel , # Log level (and tag) $disposition, # Primative part of the target (RETURN, ACCEPT, ...) - $exceptionrule # Caller's matches used in exclusion case + $exceptionrule,# Caller's matches used in exclusion case + $logname, # Name of chain to name in log messages ) = @_; my ($iiface, $diface, $inets, $dnets, $iexcl, $dexcl, $onets , $oexcl, $trivialiexcl, $trivialdexcl ); @@ -2756,28 +2758,42 @@ sub expand_rule( $$$$$$$$$$ ) if ( $loglevel ne '' ) { if ( $disposition ne 'LOG' ) { - # - # Create a chain that both logs and applies the target action - # - my $logchainref = new_chain $chainref->{table}, newlogchain; - # - # Jump to the log chain if all of the rule's conditions are met - # - add_jump( $chainref, $logchainref, $builtin_target{$disposition}, $predicates, 1 ); - # - # Now add the log rule and target rule without predicates to the log chain. - # - log_rule_limit( - $loglevel , - $chainref = $logchainref , - $chain , - $disposition , - '', - $logtag, - 'add', - '' ); + unless ( $logname ) { + # + # Create a chain that both logs and applies the target action + # + my $logchainref = new_chain $chainref->{table}, newlogchain; + # + # Jump to the log chain if all of the rule's conditions are met + # + add_jump( $chainref, $logchainref, $builtin_target{$disposition}, $predicates, 1 ); + # + # Now add the log rule and target rule without predicates to the log chain. + # + log_rule_limit( + $loglevel , + $chainref = $logchainref , + $chain , + $disposition , + '', + $logtag, + 'add', + '' ); - add_rule( $chainref, $target ); + add_rule( $chainref, $target ); + } else { + log_rule_limit( + $loglevel , + $chainref , + $logname , + $disposition , + '', + $logtag, + 'add', + $predicates ); + + add_rule( $chainref, $predicates . $target, 1 ); + } } else { # # The log rule must be added with predicates to the rule chain diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index bc36bf41e..90a74e5e7 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -1296,43 +1296,76 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) { my $nonat_chain; + my $chn; + if ( $sourceref->{type} == FIREWALL ) { $nonat_chain = $nat_table->{OUTPUT}; } else { $nonat_chain = ensure_chain 'nat', dnat_chain $sourcezone; - my $chn; + my @interfaces = keys %{zone_interfaces $sourcezone}; - for ( keys %{zone_interfaces $sourcezone} ) { + for ( @interfaces ) { my $ichain = input_chain $_; if ( $nat_table->{$ichain} ) { # # Static NAT is defined on this interface # - $chn = new_chain( 'nat', newexclusionchain ) unless $chn; - add_jump $chn, $nat_table->{$ichain}, 0, "-i $_ "; + $chn = new_chain( 'nat', newnonatchain ) unless $chn; + add_jump $chn, $nat_table->{$ichain}, 0, @interfaces > 1 ? "-i $_ " : ''; } } if ( $chn ) { - add_rule $chn, '-j ACCEPT'; + # + # Call expand_rule() to correctly handle logging. Because + # the 'logname' argument is passed, expand_rule() will + # not create a separate logging chain but will rather emit + # any logging rule in-line. + # + expand_rule( $chn, + PREROUTE_RESTRICT, + '', # Rule + '', # Source + '', # Dest + '', # Original dest + '-j ACCEPT', + $loglevel, + $log_action, + '', + dnat_chain( $sourcezone ) ); + $loglevel = ''; $tgt = $chn->{name}; } else { $tgt = 'ACCEPT'; } } - + expand_rule( $nonat_chain , PREROUTE_RESTRICT , $rule , $source , $dest , $origdest , - " -j $tgt ", + "-j $tgt", $loglevel , $log_action , - '' ); + '' + ); + # + # Possible optimization if the rule just generated was a simple jump to the nonat chain + # + if ( $chn && ${$nonat_chain->{rules}}[-1] eq "-A -j $tgt" ) { + # + # It was -- delete that rule + # + pop @{$nonat_chain->{rules}}; + # + # And move the rules from the nonat chain to the zone dnat chain + # + move_rules ( $chn, $nonat_chain ); + } } #