From 17a3ca62d5aa131a178130230d8b0e18cdb7d213 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Tue, 28 Dec 2010 13:51:45 -0800 Subject: [PATCH] Eliminate the Actions module --- Shorewall/Perl/Shorewall/Actions.pm | 285 --------------------------- Shorewall/Perl/Shorewall/Compiler.pm | 2 - Shorewall/Perl/Shorewall/Config.pm | 2 +- Shorewall/Perl/Shorewall/Misc.pm | 1 - Shorewall/Perl/Shorewall/Policy.pm | 36 +++- Shorewall/Perl/Shorewall/Rules.pm | 201 ++++++++++++++++++- 6 files changed, 229 insertions(+), 298 deletions(-) delete mode 100644 Shorewall/Perl/Shorewall/Actions.pm diff --git a/Shorewall/Perl/Shorewall/Actions.pm b/Shorewall/Perl/Shorewall/Actions.pm deleted file mode 100644 index 932d46998..000000000 --- a/Shorewall/Perl/Shorewall/Actions.pm +++ /dev/null @@ -1,285 +0,0 @@ -# -# Shorewall 4.4 -- /usr/share/shorewall/Shorewall/Actions.pm -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (c) 2007,2008,2009,2010 - Tom Eastep (teastep@shorewall.net) -# -# Complete documentation is available at http://shorewall.net -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of Version 2 of the GNU General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# This module contains the action variables and routines needed by both the Policy -# and rules modules. -# -package Shorewall::Actions; -require Exporter; -use Shorewall::Config qw(:DEFAULT :internal); -use Shorewall::Zones; -use Shorewall::Chains qw(:DEFAULT :internal); -use Shorewall::IPAddrs; -use Scalar::Util 'reftype'; - -use strict; - -our @ISA = qw(Exporter); -our @EXPORT = qw( - split_action - get_target_param - normalize_action - normalize_action_name - use_action - - %actions - %usedactions - %default_actions - ); -our @EXPORT_OK = qw( initialize ); -our $VERSION = '4.4_16'; - -# -# Default actions for each policy. -# -our %default_actions; - -# Action Table -# -# %actions{ => { requires => { = 1, -# = 1, -# ... -# } , -# actchain => # Used for generating unique chain names for each : pair. -# -our %actions; -# -# Contains an entry for each used :[:] that maps to the associated chain. -# -our %usedactions; - -our $family; - -# -# Rather than initializing globals in an INIT block or during declaration, -# we initialize them in a function. This is done for two reasons: -# -# 1. Proper initialization depends on the address family which isn't -# known until the compiler has started. -# -# 2. The compiler can run multiple times in the same process so it has to be -# able to re-initialize its dependent modules' state. -# -sub initialize( $ ) { - - $family = shift; - %default_actions = ( DROP => 'none' , - REJECT => 'none' , - ACCEPT => 'none' , - QUEUE => 'none' ); - %actions = (); - %usedactions = (); -} - -# -# Return ( action, level[:tag] ) from passed full action -# -sub split_action ( $ ) { - my $action = $_[0]; - - my $target = ''; - my $max = 3; - # - # The following rather grim RE, when matched, breaks the action into two parts: - # - # basicaction(param) - # logging part (may be empty) - # - # The param may contain one or more ':' characters - # - if ( $action =~ /^([^(:]+\(.*?\))(:(.*))?$/ ) { - $target = $1; - $action = $2 ? $3 : ''; - $max = 2; - } - - my @a = split( /:/ , $action, 4 ); - fatal_error "Invalid ACTION ($action)" if ( $action =~ /::/ ) || ( @a > $max ); - $target = shift @a unless $target; - ( $target, join ":", @a ); -} - -# -# Split the passed target into the basic target and parameter -# -sub get_target_param( $ ) { - my ( $target, $param ) = split '/', $_[0]; - - unless ( defined $param ) { - ( $target, $param ) = ( $1, $2 ) if $target =~ /^(.*?)[(](.*)[)]$/; - } - - ( $target, $param ); -} - -# -# Create a normalized action name from the passed pieces -# -sub normalize_action( $$$ ) { - my $action = shift; - my $level = shift; - my $param = shift; - - ( $level, my $tag ) = split ':', $level; - - $level = 'none' unless defined $level && $level ne ''; - $tag = '' unless defined $tag; - $param = '' unless defined $param; - - join( ':', $action, $level, $tag, $param ); -} - -sub normalize_action_name( $ ) { - my $target = shift; - my ( $action, $loglevel) = split_action $target; - - normalize_action( $action, $loglevel, '' ); - -} - -# -# Create and record a log action chain -- Log action chains have names -# that are formed from the action name by prepending a "%" and appending -# a 1- or 2-digit sequence number. In the functions that follow, -# the $chain, $level and $tag variable serves as arguments to the user's -# exit. We call the exit corresponding to the name of the action but we -# set $chain to the name of the iptables chain where rules are to be added. -# Similarly, $level and $tag contain the log level and log tag respectively. -# -# The maximum length of a chain name is 30 characters -- since the log -# action chain name is 2-3 characters longer than the base chain name, -# this function truncates the original chain name where necessary before -# it adds the leading "%" and trailing sequence number. -# -sub createlogactionchain( $$$$$ ) { - my ( $normalized, $action, $level, $tag, $param ) = @_; - my $chain = $action; - my $actionref = $actions{$action}; - my $chainref; - - validate_level $level; - - $actionref = new_action $action unless $actionref; - - $chain = substr $chain, 0, 28 if ( length $chain ) > 28; - - CHECKDUP: - { - $actionref->{actchain}++ while $chain_table{filter}{'%' . $chain . $actionref->{actchain}}; - $chain = substr( $chain, 0, 27 ), redo CHECKDUP if ( $actionref->{actchain} || 0 ) >= 10 and length $chain == 28; - } - - $usedactions{$normalized} = $chainref = new_standard_chain '%' . $chain . $actionref->{actchain}++; - - fatal_error "Too many invocations of Action $action" if $actionref->{actchain} > 99; - - $chainref->{action} = $action; - - unless ( $targets{$action} & BUILTIN ) { - - dont_optimize $chainref; - - my $file = find_file $chain; - - if ( -f $file ) { - progress_message "Processing $file..."; - - my @params = split /,/, $param; - - unless ( my $return = eval `cat $file` ) { - fatal_error "Couldn't parse $file: $@" if $@; - fatal_error "Couldn't do $file: $!" unless defined $return; - fatal_error "Couldn't run $file"; - } - } - } - - $chainref; -} - -sub createsimpleactionchain( $ ) { - my $action = shift; - - return createlogactionchain("$action:none::", $action, 'none', '', '' ) if $filter_table->{$action} || $nat_table->{$action}; - - my $chainref = new_standard_chain $action; - - $usedactions{"$action:none::"} = $chainref; - - $chainref->{action} = $action; - - unless ( $targets{$action} & BUILTIN ) { - - dont_optimize $chainref; - - my $file = find_file $action; - - if ( -f $file ) { - progress_message "Processing $file..."; - - my ( $level, $tag ) = ( '', '' ); - - unless ( my $return = eval `cat $file` ) { - fatal_error "Couldn't parse $file: $@" if $@; - fatal_error "Couldn't do $file: $!" unless defined $return; - fatal_error "Couldn't run $file"; - } - } - } - - $chainref; -} - -# -# Create an action chain and run its associated user exit -# -sub createactionchain( $ ) { - my $normalized = shift; - - my ( $target, $level, $tag, $param ) = split /:/, $normalized; - - assert( defined $param ); - - my $chainref; - - if ( $level eq 'none' && $tag eq '' && $param eq '' ) { - createsimpleactionchain $target; - } else { - createlogactionchain $normalized, $target , $level , $tag, $param; - } -} - -# -# Mark an action as used and create its chain. Returns one if the chain was -# created on this call or 0 otherwise. -# -sub use_action( $ ) { - my $normalized = shift; - - if ( $usedactions{$normalized} ) { - 0; - } else { - createactionchain $normalized; - } -} - -1; diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 062a5546c..74a9520a2 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -32,7 +32,6 @@ use Shorewall::Nat; use Shorewall::Providers; use Shorewall::Tc; use Shorewall::Tunnels; -use Shorewall::Actions; use Shorewall::Accounting; use Shorewall::Rules; use Shorewall::Proc; @@ -63,7 +62,6 @@ sub initialize_package_globals() { Shorewall::Nat::initialize; Shorewall::Providers::initialize($family); Shorewall::Tc::initialize($family); - Shorewall::Actions::initialize( $family ); Shorewall::Accounting::initialize; Shorewall::Rules::initialize($family); Shorewall::Proxyarp::initialize($family); diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index 19be2d1f2..fde1c6559 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -1629,7 +1629,7 @@ sub close_file() { # # The following two functions allow module clients to nest opens. This happens frequently -# in the Actions module. +# in the Rules module. # sub push_open( $ ) { diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index 61fdc6c88..ec48419cf 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -29,7 +29,6 @@ use Shorewall::Config qw(:DEFAULT :internal); use Shorewall::IPAddrs; use Shorewall::Zones; use Shorewall::Chains qw(:DEFAULT :internal); -use Shorewall::Actions; use Shorewall::Policy; use Shorewall::Proc; diff --git a/Shorewall/Perl/Shorewall/Policy.pm b/Shorewall/Perl/Shorewall/Policy.pm index 9d7548fb2..b72032959 100644 --- a/Shorewall/Perl/Shorewall/Policy.pm +++ b/Shorewall/Perl/Shorewall/Policy.pm @@ -27,12 +27,11 @@ require Exporter; use Shorewall::Config qw(:DEFAULT :internal); use Shorewall::Zones; use Shorewall::Chains qw( :DEFAULT :internal) ; -use Shorewall::Actions; use strict; our @ISA = qw(Exporter); -our @EXPORT = qw( validate_policy apply_policy_rules complete_standard_chain setup_syn_flood_chains save_policies optimize_policy_chains); +our @EXPORT = qw( validate_policy apply_policy_rules complete_standard_chain setup_syn_flood_chains save_policies optimize_policy_chains get_target_param %policy_actions ); our @EXPORT_OK = qw( ); our $VERSION = '4.4_16'; @@ -40,11 +39,32 @@ our $VERSION = '4.4_16'; our @policy_chains; +our %policy_actions; + +our %default_actions; # # Called by the compiler # sub initialize() { - @policy_chains = (); + @policy_chains = (); + %policy_actions = (); + %default_actions = ( DROP => 'none' , + REJECT => 'none' , + ACCEPT => 'none' , + QUEUE => 'none' ); +} + +# +# Split the passed target into the basic target and parameter +# +sub get_target_param( $ ) { + my ( $target, $param ) = split '/', $_[0]; + + unless ( defined $param ) { + ( $target, $param ) = ( $1, $2 ) if $target =~ /^(.*?)[(](.*)[)]$/; + } + + ( $target, $param ); } # @@ -143,6 +163,12 @@ sub print_policy($$$$) { } } +sub use_action( $ ) { + my $action = shift; + + $policy_actions{$action} = 1; +} + sub process_a_policy() { our %validpolicies; @@ -177,7 +203,7 @@ sub process_a_policy() { my $defaulttype = $targets{$default} || 0; if ( $defaulttype & ACTION ) { - use_action( normalize_action_name $default ); + use_action( $default ); } else { fatal_error "Unknown Default Action ($default)"; } @@ -318,7 +344,7 @@ sub validate_policy() fatal_error "Default Action $option=$action not found"; } - use_action( normalize_action_name $action ); + use_action( $action ); $default_actions{$map{$option}} = $action; } diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index 68d0b5306..f4d293881 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -28,7 +28,6 @@ require Exporter; use Shorewall::Config qw(:DEFAULT :internal); use Shorewall::Zones; use Shorewall::Chains qw(:DEFAULT :internal); -use Shorewall::Actions; use Shorewall::IPAddrs; use Shorewall::Policy; use Scalar::Util 'reftype'; @@ -64,6 +63,20 @@ our $macro_nest_level; our @actionstack; +# Action Table +# +# %actions{ => { requires => { = 1, +# = 1, +# ... +# } , +# actchain => # Used for generating unique chain names for each : pair. +# +our %actions; +# +# Contains an entry for each used :[:] that maps to the associated chain. +# +our %usedactions; + # # Rather than initializing globals in an INIT block or during declaration, # we initialize them in a function. This is done for two reasons: @@ -79,6 +92,8 @@ sub initialize( $ ) { %macros = (); @actionstack = (); $macro_nest_level = 0; + %actions = (); + %usedactions = (); if ( $family == F_IPV4 ) { @builtins = qw/dropBcast allowBcast dropNotSyn rejNotSyn dropInvalid allowInvalid allowinUPnP forwardUPnP Limit/; @@ -87,6 +102,185 @@ sub initialize( $ ) { } } +# +# Return ( action, level[:tag] ) from passed full action +# +sub split_action ( $ ) { + my $action = $_[0]; + + my $target = ''; + my $max = 3; + # + # The following rather grim RE, when matched, breaks the action into two parts: + # + # basicaction(param) + # logging part (may be empty) + # + # The param may contain one or more ':' characters + # + if ( $action =~ /^([^(:]+\(.*?\))(:(.*))?$/ ) { + $target = $1; + $action = $2 ? $3 : ''; + $max = 2; + } + + my @a = split( /:/ , $action, 4 ); + fatal_error "Invalid ACTION ($action)" if ( $action =~ /::/ ) || ( @a > $max ); + $target = shift @a unless $target; + ( $target, join ":", @a ); +} + +# +# Create a normalized action name from the passed pieces +# +sub normalize_action( $$$ ) { + my $action = shift; + my $level = shift; + my $param = shift; + + ( $level, my $tag ) = split ':', $level; + + $level = 'none' unless defined $level && $level ne ''; + $tag = '' unless defined $tag; + $param = '' unless defined $param; + + join( ':', $action, $level, $tag, $param ); +} + +sub normalize_action_name( $ ) { + my $target = shift; + my ( $action, $loglevel) = split_action $target; + + normalize_action( $action, $loglevel, '' ); + +} + +# +# Create and record a log action chain -- Log action chains have names +# that are formed from the action name by prepending a "%" and appending +# a 1- or 2-digit sequence number. In the functions that follow, +# the $chain, $level and $tag variable serves as arguments to the user's +# exit. We call the exit corresponding to the name of the action but we +# set $chain to the name of the iptables chain where rules are to be added. +# Similarly, $level and $tag contain the log level and log tag respectively. +# +# The maximum length of a chain name is 30 characters -- since the log +# action chain name is 2-3 characters longer than the base chain name, +# this function truncates the original chain name where necessary before +# it adds the leading "%" and trailing sequence number. +# +sub createlogactionchain( $$$$$ ) { + my ( $normalized, $action, $level, $tag, $param ) = @_; + my $chain = $action; + my $actionref = $actions{$action}; + my $chainref; + + validate_level $level; + + $actionref = new_action $action unless $actionref; + + $chain = substr $chain, 0, 28 if ( length $chain ) > 28; + + CHECKDUP: + { + $actionref->{actchain}++ while $chain_table{filter}{'%' . $chain . $actionref->{actchain}}; + $chain = substr( $chain, 0, 27 ), redo CHECKDUP if ( $actionref->{actchain} || 0 ) >= 10 and length $chain == 28; + } + + $usedactions{$normalized} = $chainref = new_standard_chain '%' . $chain . $actionref->{actchain}++; + + fatal_error "Too many invocations of Action $action" if $actionref->{actchain} > 99; + + $chainref->{action} = $action; + + unless ( $targets{$action} & BUILTIN ) { + + dont_optimize $chainref; + + my $file = find_file $chain; + + if ( -f $file ) { + progress_message "Processing $file..."; + + my @params = split /,/, $param; + + unless ( my $return = eval `cat $file` ) { + fatal_error "Couldn't parse $file: $@" if $@; + fatal_error "Couldn't do $file: $!" unless defined $return; + fatal_error "Couldn't run $file"; + } + } + } + + $chainref; +} + +sub createsimpleactionchain( $ ) { + my $action = shift; + + return createlogactionchain("$action:none::", $action, 'none', '', '' ) if $filter_table->{$action} || $nat_table->{$action}; + + my $chainref = new_standard_chain $action; + + $usedactions{"$action:none::"} = $chainref; + + $chainref->{action} = $action; + + unless ( $targets{$action} & BUILTIN ) { + + dont_optimize $chainref; + + my $file = find_file $action; + + if ( -f $file ) { + progress_message "Processing $file..."; + + my ( $level, $tag ) = ( '', '' ); + + unless ( my $return = eval `cat $file` ) { + fatal_error "Couldn't parse $file: $@" if $@; + fatal_error "Couldn't do $file: $!" unless defined $return; + fatal_error "Couldn't run $file"; + } + } + } + + $chainref; +} + +# +# Create an action chain and run its associated user exit +# +sub createactionchain( $ ) { + my $normalized = shift; + + my ( $target, $level, $tag, $param ) = split /:/, $normalized; + + assert( defined $param ); + + my $chainref; + + if ( $level eq 'none' && $tag eq '' && $param eq '' ) { + createsimpleactionchain $target; + } else { + createlogactionchain $normalized, $target , $level , $tag, $param; + } +} + +# +# Mark an action as used and create its chain. Returns one if the chain was +# created on this call or 0 otherwise. +# +sub use_action( $ ) { + my $normalized = shift; + + if ( $usedactions{$normalized} ) { + 0; + } else { + createactionchain $normalized; + } +} + # # This function determines the logging and params for a subordinate action or a rule within a superior action # @@ -379,9 +573,8 @@ sub process_action2( $ ) { sub process_actions2 () { progress_message2 "Pre-processing default actions..."; - for my $action ( keys %usedactions ) { - my ( $basic_action, undef, undef, undef ) = split /:/, $action; - process_action2( $action ) unless $targets{$basic_action} & BUILTIN; + for my $action ( map normalize_action_name $_, ( grep ! ( $targets{$_} & BUILTIN ), keys %policy_actions ) ) { + process_action2( $action ) if use_action( $action ); } }