From b5af6f03fb06f72a71057a1b29bb2d70bbd8b31a Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Sat, 11 Aug 2012 07:48:03 -0700 Subject: [PATCH] Create better rules when a HELPER appears in an action Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Chains.pm | 2 + Shorewall/Perl/Shorewall/Raw.pm | 88 ++++++++++++++++++++++++++---- Shorewall/Perl/Shorewall/Rules.pm | 63 ++++++++++++--------- Shorewall/Perl/Shorewall/Zones.pm | 3 +- 4 files changed, 117 insertions(+), 39 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 779254dd1..3bbdb0e01 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -101,6 +101,7 @@ our %EXPORT_TAGS = ( CHAIN SET AUDIT + HELPER NO_RESTRICT PREROUTE_RESTRICT DESTIFACE_DISALLOW @@ -352,6 +353,7 @@ use constant { STANDARD => 1, #defined by Netfilter CHAIN => 1024, #Manual Chain SET => 2048, #SET AUDIT => 4096, #A_ACCEPT, etc + HELPER => 8192, #CT:helper }; # # Valid Targets -- value is a combination of one or more of the above diff --git a/Shorewall/Perl/Shorewall/Raw.pm b/Shorewall/Perl/Shorewall/Raw.pm index cc3b78cba..284163ede 100644 --- a/Shorewall/Perl/Shorewall/Raw.pm +++ b/Shorewall/Perl/Shorewall/Raw.pm @@ -33,7 +33,7 @@ use strict; our @ISA = qw(Exporter); our @EXPORT = qw( setup_conntrack ); -our @EXPORT_OK = qw( process_conntrack_rule ); +our @EXPORT_OK = qw( handle_helper_rule ); our $VERSION = 'MODULEVERSION'; my %valid_ctevent = ( new => 1, related => 1, destroy => 1, reply => 1, assured => 1, protoinfo => 1, helper => 1, mark => 1, natseqinfo => 1, secmark => 1 ); @@ -41,21 +41,34 @@ my %valid_ctevent = ( new => 1, related => 1, destroy => 1, reply => 1, assured # # Notrack # -sub process_conntrack_rule( $$$$$$$ ) { +sub process_conntrack_rule( $$$$$$$$$ ) { - my ($action, $source, $dest, $proto, $ports, $sports, $user ) = @_; + my ($chainref, $zoneref, $action, $source, $dest, $proto, $ports, $sports, $user ) = @_; + + require_capability 'RAW_TABLE', 'conntrack rules', ''; $proto = '' if $proto eq 'any'; $ports = '' if $ports eq 'any' || $ports eq 'all'; $sports = '' if $sports eq 'any' || $sports eq 'all'; - ( my $zone, $source) = split /:/, $source, 2; - my $zoneref = find_zone $zone; - my $chainref = ensure_raw_chain( notrack_chain $zone ); - my $restriction = $zoneref->{type} == FIREWALL || $zoneref->{type} == VSERVER ? OUTPUT_RESTRICT : PREROUTE_RESTRICT; + my $zone; + my $restriction = PREROUTE_RESTRICT; - fatal_error 'USER/GROUP is not allowed unless the SOURCE zone is $FW or a Vserver zone' if $user ne '-' && $restriction != OUTPUT_RESTRICT; - require_capability 'RAW_TABLE', 'conntrack rules', ''; + unless ( $chainref ) { + # + # Entry in the conntrack file + # + if ( $zoneref ) { + $zone = $zoneref->{name}; + } else { + ($zone, $source) = split /:/, $source, 2; + $zoneref = find_zone ( $zone ); + } + + $chainref = ensure_raw_chain( notrack_chain $zone ); + $restriction = OUTPUT_RESTRICT if $zoneref->{type} == FIREWALL || $zoneref->{type} == VSERVER; + fatal_error 'USER/GROUP is not allowed unless the SOURCE zone is $FW or a Vserver zone' if $user ne '-' && $restriction != OUTPUT_RESTRICT; + } my $target = $action; my $exception_rule = ''; @@ -125,6 +138,59 @@ sub process_conntrack_rule( $$$$$$$ ) { progress_message " Conntrack rule \"$currentline\" $done"; } +sub handle_helper_rule( $$$$$$$$$$$ ) { + my ( $helper, $source, $dest, $proto, $ports, $sports, $sourceref, $action_target, $actionchain, $user, $rule ) = @_; + + if ( $helper ne '-' ) { + fatal_error "A HELPER is not allowed with this ACTION" if $action_target; + # + # This means that an ACCEPT or NAT rule with a helper is being processed + # + process_conntrack_rule( $actionchain ? ensure_raw_chain( $actionchain ) : undef , + $sourceref , + "CT:helper:$helper", + $source , + $dest , + $proto , + $ports , + $sports , + $user ); + } else { + assert( $action_target ); + # + # The target is an action + # + if ( $actionchain ) { + # + # And the source is another action chain + # + expand_rule( ensure_raw_chain( $actionchain ) , + PREROUTE_RESTRICT , + $rule , + $source , + $dest , + '' , + $action_target , + '', + 'CT' , + '' ); + } else { + expand_rule( ensure_raw_chain( notrack_chain( $sourceref->{name} ) ) , + ( $sourceref->{type} == FIREWALL || $sourceref->{type} == VSERVER ? + OUTPUT_RESTRICT : + PREROUTE_RESTRICT ) , + $rule , + $source , + $dest , + '' , + $action_target , + '' , + 'CT' , + '' ); + } + } +} + sub process_format( $ ) { my $format = shift; @@ -186,10 +252,10 @@ sub setup_conntrack() { if ( $source eq 'all' ) { for my $zone (all_zones) { - process_conntrack_rule( $action, $zone, $dest, $proto, $ports, $sports, $user ); + process_conntrack_rule( undef, undef, $action, $zone, $dest, $proto, $ports, $sports, $user ); } } else { - process_conntrack_rule( $action, $source, $dest, $proto, $ports, $sports, $user ); + process_conntrack_rule( undef, undef, $action, $source, $dest, $proto, $ports, $sports, $user ); } } diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index 3befde4a9..462e4c50a 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -34,7 +34,7 @@ use Shorewall::Zones; use Shorewall::Chains qw(:DEFAULT :internal); use Shorewall::IPAddrs; use Shorewall::Nat qw(:rules); -use Shorewall::Raw qw( process_conntrack_rule ); +use Shorewall::Raw qw( handle_helper_rule ); use Scalar::Util 'reftype'; use strict; @@ -1783,12 +1783,13 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { # process_action( $ref ); # - # Processing the action may determine that the action or one of it's dependents does NAT, so: + # Processing the action may determine that the action or one of it's dependents does NAT or HELPER, so: # # - Refresh $actiontype - # - Create the associate nat table chain if appropriate. + # - Create the associated nat and/or table chain if appropriate. # ensure_chain( 'nat', $ref->{name} ) if ( $actiontype = $targets{$basictarget} ) & NATRULE; + ensure_chain( 'raw', $ref->{name} ) if ( $actiontype & HELPER ); } $action = $basictarget; # Remove params, if any, from $action. @@ -1803,6 +1804,10 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { $targets{$inaction} |= NATRULE if $inaction; fatal_error "NAT rules are only allowed in the NEW section" unless $section eq 'NEW'; } + + if ( $actiontype & HELPER ) { + fatal_error "HELPER rules are only allowed in the NEW section" unless $section eq 'NEW'; + } # # Take care of irregular syntax and targets # @@ -1814,7 +1819,13 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { $bt =~ s/[-+!]$//; my %functions = - ( ACCEPT => sub() { $action = 'RETURN' if $blacklist; } , + ( ACCEPT => sub() { + if ( $blacklist ) { + $action = 'RETURN'; + } elsif ( $helper ne '-' ) { + $actiontype |= HELPER; + } + } , REDIRECT => sub () { my $z = $actiontype & NATONLY ? '' : firewall_zone; @@ -1845,6 +1856,8 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { if ( $function ) { $function->(); + } elsif ( $actiontype & NATRULE && $helper ne '-' ) { + $actiontype |= HELPER; } elsif ( $actiontype & SET ) { my %xlate = ( ADD => 'add-set' , DEL => 'del-set' ); @@ -2034,8 +2047,26 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { fatal_error "$basictarget rules are not allowed in the $section SECTION" if $actiontype & ( NATRULE | NONAT ); $rule .= "$globals{STATEMATCH} $section " unless $section eq 'ALL' || $blacklist; } - # + # Generate CT rules(s), if any + # + if ( $actiontype & HELPER ) { + handle_helper_rule( $helper, + $source, + $origdest ? $origdest : $dest, + $proto, + $ports, + $sports, + $sourceref, + ( $actiontype & ACTION ) ? $usedactions{$normalized_target}->{name} : '', + $inaction ? $chain : '' , + $user , + $rule , + ); + + $targets{$inaction} |= HELPER if $inaction; + } + # Generate NAT rule(s), if any # if ( $actiontype & NATRULE ) { @@ -2059,17 +2090,6 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { $log_action, ); - unless ( $helper eq '-' ) { - my $rulezone = $inaction ? 'all' : $sourcezone; - - process_conntrack_rule( "CT:helper:$helper" , - "$rulezone:$source", - $origdest, - $proto, - $ports, - $sports, - $user ); - } # # After NAT: # - the destination port will be the server port ($ports) -- we did that above @@ -2141,17 +2161,6 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) { $loglevel , $log_action , '' ); - - if ( $action eq 'ACCEPT' && $helper ne '-' ) { - my $rulezone = $inaction ? 'all' : $sourcezone; - process_conntrack_rule( "CT:helper:$helper" , - "$rulezone:$source", - $origdest ? $origdest : $dest, - $proto, - $ports, - $sports, - $user ); - } } return 1; diff --git a/Shorewall/Perl/Shorewall/Zones.pm b/Shorewall/Perl/Shorewall/Zones.pm index 87c667710..df9326c70 100644 --- a/Shorewall/Perl/Shorewall/Zones.pm +++ b/Shorewall/Perl/Shorewall/Zones.pm @@ -118,7 +118,8 @@ use constant { IN_OUT => 1, # # @zones contains the ordered list of zones with sub-zones appearing before their parents. # -# %zones{ => {type => FIREWALL, IP, IPSEC, BPORT; +# %zones{ => {name => , +# type => FIREWALL, IP, IPSEC, BPORT; # complex => 0|1 # super => 0|1 # options => { in_out => < policy match string >