mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-22 14:20:40 +01:00
Implement inline actions.
Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
parent
85a46690c0
commit
6bf996d4b8
@ -104,6 +104,7 @@ our %EXPORT_TAGS = (
|
||||
SET
|
||||
AUDIT
|
||||
HELPER
|
||||
INLINE
|
||||
NO_RESTRICT
|
||||
PREROUTE_RESTRICT
|
||||
DESTIFACE_DISALLOW
|
||||
@ -359,6 +360,7 @@ use constant { STANDARD => 1, #defined by Netfilter
|
||||
AUDIT => 4096, #A_ACCEPT, etc
|
||||
HELPER => 8192, #CT:helper
|
||||
NFLOG => 16384, #NFLOG or ULOG
|
||||
INLINE => 32768, #Inline action
|
||||
};
|
||||
#
|
||||
# Valid Targets -- value is a combination of one or more of the above
|
||||
@ -2443,11 +2445,16 @@ sub require_audit($$;$) {
|
||||
sub get_action_logging() {
|
||||
my $chainref = get_action_chain;
|
||||
my $wholeaction = $chainref->{action};
|
||||
my ( undef, $level, $tag, undef ) = split ':', $wholeaction;
|
||||
|
||||
$level = '' if $level =~ /^none/;
|
||||
if ( $wholeaction ) {
|
||||
my ( undef, $level, $tag, undef ) = split ':', $wholeaction;
|
||||
|
||||
( $level, $tag );
|
||||
$level = '' if $level =~ /^none/;
|
||||
|
||||
( $level, $tag );
|
||||
} else {
|
||||
( '' , '' );
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -96,7 +96,7 @@ my %rulecolumns = ( action => 0,
|
||||
helper => 14,
|
||||
);
|
||||
|
||||
use constant { MAX_MACRO_NEST_LEVEL => 5 };
|
||||
use constant { MAX_MACRO_NEST_LEVEL => 10 };
|
||||
|
||||
my $macro_nest_level;
|
||||
|
||||
@ -109,6 +109,10 @@ my %active;
|
||||
#
|
||||
my %actions;
|
||||
#
|
||||
# Inline Action Table
|
||||
#
|
||||
my %inlines;
|
||||
#
|
||||
# Contains an entry for each used <action>:<level>[:<tag>] that maps to the associated chain.
|
||||
#
|
||||
my %usedactions;
|
||||
@ -178,6 +182,10 @@ sub initialize( $ ) {
|
||||
#
|
||||
%actions = ();
|
||||
#
|
||||
# Inline Actions -- value is file.
|
||||
#
|
||||
%inlines = ();
|
||||
#
|
||||
# Action variants actually used. Key is <action>:<loglevel>:<tag>:<params>; value is corresponding chain name
|
||||
#
|
||||
%usedactions = ();
|
||||
@ -335,9 +343,12 @@ sub process_default_action( $$$$ ) {
|
||||
$level eq 'none' ? normalize_action_name $def :
|
||||
normalize_action( $def, $level, '' );
|
||||
use_policy_action( $default );
|
||||
} elsif ( find_macro( $def ) ) {
|
||||
} elsif ( find_macro( $def )) {
|
||||
$default = join( '.', 'macro', $def ) unless $default =~ /^macro./;
|
||||
$default = "$def($param)" if supplied $param;
|
||||
} elsif ( ( $targets{$def} || 0 ) == INLINE ) {
|
||||
$default = $def;
|
||||
$default = "$def($param)" if supplied $param;
|
||||
} elsif ( $default_option ) {
|
||||
fatal_error "Unknown Action ($default) in $policy setting";
|
||||
} else {
|
||||
@ -571,7 +582,8 @@ sub process_policies()
|
||||
#
|
||||
# Policy Rule application
|
||||
#
|
||||
sub process_macro ($$$$$$$$$$$$$$$$$$$);
|
||||
sub process_macro ($$$$$$$$$$$$$$$$$$$);
|
||||
sub process_inline ($$$$$$$$$$$$$$$$$$$);
|
||||
|
||||
sub policy_rules( $$$$$ ) {
|
||||
my ( $chainref , $target, $loglevel, $default, $dropmulticast ) = @_;
|
||||
@ -609,10 +621,37 @@ sub policy_rules( $$$$$ ) {
|
||||
0, #Wildcard
|
||||
);
|
||||
} else {
|
||||
#
|
||||
# Default action is an action -- jump to the action chain
|
||||
#
|
||||
add_ijump $chainref, j => $default;
|
||||
my ( $inline ) = split ':', $default;
|
||||
|
||||
( $inline, my $param ) = get_target_param( $inline );
|
||||
|
||||
if ( $targets{$inline} == INLINE ) {
|
||||
process_inline( $inline, #Inline
|
||||
$chainref, #Chain
|
||||
$default, #Target
|
||||
$param || '', #Param
|
||||
'-', #Source
|
||||
'-', #Dest
|
||||
'-', #Proto
|
||||
'-', #Ports
|
||||
'-', #Sports
|
||||
'-', #Original Dest
|
||||
'-', #Rate
|
||||
'-', #User
|
||||
'-', #Mark
|
||||
'-', #ConnLimit
|
||||
'-', #Time
|
||||
'-', #Headers
|
||||
'-', #Condition
|
||||
'-', #Helper
|
||||
0, #Wildcard
|
||||
);
|
||||
} else {
|
||||
#
|
||||
# Default action is an action -- jump to the action chain
|
||||
#
|
||||
add_ijump $chainref, j => $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -984,7 +1023,7 @@ sub new_action( $$ ) {
|
||||
|
||||
fatal_error "Invalid action name($action)" if reserved_name( $action );
|
||||
|
||||
$actions{$action} = { actchain => '' };
|
||||
$actions{$action} = { actchain => '' } if $type & ACTION;
|
||||
|
||||
$targets{$action} = $type;
|
||||
}
|
||||
@ -1126,6 +1165,8 @@ sub use_action( $ ) {
|
||||
sub merge_levels ($$) {
|
||||
my ( $superior, $subordinate ) = @_;
|
||||
|
||||
return $subordinate if $subordinate =~ /^(?:FORMAT|COMMENT|DEFAULTS?)$/;
|
||||
|
||||
my @supparts = split /:/, $superior;
|
||||
my @subparts = split /:/, $subordinate;
|
||||
|
||||
@ -1471,27 +1512,35 @@ sub process_actions() {
|
||||
open_file $file;
|
||||
|
||||
while ( read_a_line( NORMAL_READ ) ) {
|
||||
my ( $action ) = split_line 'action file' , { action => 0 };
|
||||
my ( $action, $options ) = split_line 'action file' , { action => 0, options => 1 };
|
||||
|
||||
my $type = ACTION;
|
||||
|
||||
if ( $action =~ /:/ ) {
|
||||
warning_message 'Default Actions are now specified in /etc/shorewall/shorewall.conf';
|
||||
$action =~ s/:.*$//;
|
||||
}
|
||||
|
||||
fatal_error "Invalid Action Name ($action)" unless $action =~ /^[\w-]+$/;
|
||||
fatal_error "Invalid Action Name ($action)" unless $action =~ /^[a-zA-Z][\w-]*$/;
|
||||
|
||||
if ( $targets{$action} ) {
|
||||
warning_message "Duplicate Action Name ($action) Ignored" unless $targets{$action} & ACTION;
|
||||
warning_message "Duplicate Action Name ($action) Ignored" unless $targets{$action} & ( ACTION | INLINE );
|
||||
next;
|
||||
}
|
||||
|
||||
fatal_error "Invalid Action Name ($action)" unless "\L$action" =~ /^[a-z]\w*$/;
|
||||
if ( $options eq 'inline' ) {
|
||||
$type = INLINE;
|
||||
} else {
|
||||
fatal_error "Invalid option($options)" unless $options eq '-';
|
||||
}
|
||||
|
||||
new_action $action, ACTION;
|
||||
new_action $action, $type;
|
||||
|
||||
my $actionfile = find_file "action.$action";
|
||||
|
||||
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
|
||||
|
||||
$inlines{$action} = $actionfile if $type == INLINE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1748,6 +1797,131 @@ sub process_macro ($$$$$$$$$$$$$$$$$$$) {
|
||||
return $generated;
|
||||
}
|
||||
|
||||
#
|
||||
# Expand a macro rule from the rules file
|
||||
#
|
||||
sub process_inline ($$$$$$$$$$$$$$$$$$$) {
|
||||
my ($inline, $chainref, $target, $param, $source, $dest, $proto, $ports, $sports, $origdest, $rate, $user, $mark, $connlimit, $time, $headers, $condition, $helper, $wildcard ) = @_;
|
||||
|
||||
my $nocomment = no_comment;
|
||||
|
||||
my $generated = 0;
|
||||
|
||||
macro_comment $inline;
|
||||
|
||||
my $oldparms = push_action_params( $chainref, $param );
|
||||
|
||||
my $inlinefile = $inlines{$inline};
|
||||
|
||||
progress_message "..Expanding inline action $inlinefile...";
|
||||
|
||||
push_open $inlinefile;
|
||||
|
||||
while ( read_a_line( NORMAL_READ ) ) {
|
||||
my ( $mtarget,
|
||||
$msource,
|
||||
$mdest,
|
||||
$mproto,
|
||||
$mports,
|
||||
$msports,
|
||||
$morigdest,
|
||||
$mrate,
|
||||
$muser,
|
||||
$mmark,
|
||||
$mconnlimit,
|
||||
$mtime,
|
||||
$mheaders,
|
||||
$mcondition,
|
||||
$mhelper ) = split_line1 'inline action file', \%rulecolumns, $rule_commands;
|
||||
|
||||
fatal_error 'TARGET must be specified' if $mtarget eq '-';
|
||||
|
||||
if ( $mtarget eq 'COMMENT' ) {
|
||||
process_comment unless $nocomment;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $mtarget eq 'DEFAULTS' ) {
|
||||
default_action_params( $chainref, split_list( $msource, 'defaults' ) );
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $mtarget eq 'FORMAT' ) {
|
||||
fatal_error "FORMAT must be 2" unless $source ne '2';
|
||||
next;
|
||||
}
|
||||
|
||||
$mtarget = merge_levels $target, $mtarget;
|
||||
|
||||
my $action = isolate_basic_target $mtarget;
|
||||
|
||||
fatal_error "Invalid or missing ACTION ($mtarget)" unless defined $action;
|
||||
|
||||
my $actiontype = $targets{$action} || find_macro( $action );
|
||||
|
||||
fatal_error( "Invalid Action ($mtarget) in inline action", $inline ) unless $actiontype & ( ACTION + STANDARD + NATRULE + MACRO + CHAIN + INLINE );
|
||||
|
||||
if ( $msource ) {
|
||||
if ( $msource eq '-' ) {
|
||||
$msource = $source || '';
|
||||
} elsif ( $msource =~ s/^DEST:?// ) {
|
||||
$msource = merge_macro_source_dest $msource, $dest;
|
||||
} else {
|
||||
$msource =~ s/^SOURCE:?//;
|
||||
$msource = merge_macro_source_dest $msource, $source;
|
||||
}
|
||||
} else {
|
||||
$msource = '';
|
||||
}
|
||||
|
||||
if ( $mdest ) {
|
||||
if ( $mdest eq '-' ) {
|
||||
$mdest = $dest || '';
|
||||
} elsif ( $mdest =~ s/^SOURCE:?// ) {
|
||||
$mdest = merge_macro_source_dest $mdest , $source;
|
||||
} else {
|
||||
$mdest =~ s/DEST:?//;
|
||||
$mdest = merge_macro_source_dest $mdest, $dest;
|
||||
}
|
||||
} else {
|
||||
$mdest = '';
|
||||
}
|
||||
|
||||
$generated |= process_rule1(
|
||||
$chainref,
|
||||
$mtarget,
|
||||
$param,
|
||||
$msource,
|
||||
$mdest,
|
||||
merge_macro_column( $mproto, $proto ) ,
|
||||
merge_macro_column( $mports, $ports ) ,
|
||||
merge_macro_column( $msports, $sports ) ,
|
||||
merge_macro_column( $morigdest, $origdest ) ,
|
||||
merge_macro_column( $mrate, $rate ) ,
|
||||
merge_macro_column( $muser, $user ) ,
|
||||
merge_macro_column( $mmark, $mark ) ,
|
||||
merge_macro_column( $mconnlimit, $connlimit) ,
|
||||
merge_macro_column( $mtime, $time ),
|
||||
merge_macro_column( $mheaders, $headers ),
|
||||
merge_macro_column( $mcondition, $condition ),
|
||||
merge_macro_column( $mhelper, $helper ),
|
||||
$wildcard
|
||||
);
|
||||
|
||||
progress_message " Rule \"$currentline\" $done";
|
||||
}
|
||||
|
||||
pop_open;
|
||||
|
||||
progress_message "..End inline action $inlinefile";
|
||||
|
||||
pop_action_params( $oldparms );
|
||||
|
||||
clear_comment unless $nocomment;
|
||||
|
||||
return $generated;
|
||||
}
|
||||
|
||||
#
|
||||
# Confirm that we have AUDIT_TARGET capability and ensure the appropriate AUDIT chain.
|
||||
#
|
||||
@ -1818,7 +1992,7 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
#
|
||||
# process_macro() will call process_rule1() recursively for each rule in the macro body
|
||||
#
|
||||
fatal_error "Macro invocations nested too deeply" if ++$macro_nest_level > MAX_MACRO_NEST_LEVEL;
|
||||
fatal_error "Macro/Inline invocations nested too deeply" if ++$macro_nest_level > MAX_MACRO_NEST_LEVEL;
|
||||
|
||||
$current_param = $param unless $param eq '' || $param eq 'PARAM';
|
||||
|
||||
@ -1846,7 +2020,7 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
|
||||
return $generated;
|
||||
|
||||
} elsif ( $actiontype & ACTION ) {
|
||||
} elsif ( $actiontype & ( ACTION | INLINE ) ) {
|
||||
split_list $param, 'Action parameter';
|
||||
} elsif ( $actiontype & NFQ ) {
|
||||
require_capability( 'NFQUEUE_TARGET', 'NFQUEUE Rules', '' );
|
||||
@ -1920,7 +2094,7 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
#
|
||||
my $log_action = $action;
|
||||
|
||||
unless ( $actiontype & ( ACTION | MACRO | NFLOG | NFQ | CHAIN ) ) {
|
||||
unless ( $actiontype & ( ACTION | MACRO | NFLOG | NFQ | CHAIN | INLINE ) ) {
|
||||
my $bt = $basictarget;
|
||||
|
||||
$bt =~ s/[-+!]$//;
|
||||
@ -2065,6 +2239,10 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
# We are generating rules in a chain -- get its name
|
||||
#
|
||||
$chain = $chainref->{name};
|
||||
#
|
||||
# If we are processing an inline action, we need the source zone for NAT.
|
||||
#
|
||||
$sourceref = find_zone( $chainref->{sourcezone} ) if $chainref->{sourcezone};
|
||||
} else {
|
||||
unless ( $actiontype & NATONLY ) {
|
||||
#
|
||||
@ -2081,7 +2259,8 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
#
|
||||
# Ensure that the chain exists but don't mark it as referenced until after optimization is checked
|
||||
#
|
||||
$chainref = ensure_chain 'filter', $chain;
|
||||
( $chainref = ensure_chain( 'filter', $chain ) )->{sourcezone} = $sourcezone;
|
||||
|
||||
my $policy = $chainref->{policy};
|
||||
|
||||
if ( $policy eq 'NONE' ) {
|
||||
@ -2123,6 +2302,39 @@ sub process_rule1 ( $$$$$$$$$$$$$$$$$$ ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $actiontype & INLINE ) {
|
||||
#
|
||||
# process_inline() will call process_rule1() recursively for each rule in the macro body
|
||||
#
|
||||
fatal_error "Macro/Inline invocations nested too deeply" if ++$macro_nest_level > MAX_MACRO_NEST_LEVEL;
|
||||
|
||||
$current_param = $param unless $param eq '' || $param eq 'PARAM';
|
||||
|
||||
my $generated = process_inline( $basictarget,
|
||||
$chainref,
|
||||
$target,
|
||||
$current_param,
|
||||
$source,
|
||||
$dest,
|
||||
$proto,
|
||||
$ports,
|
||||
$sports,
|
||||
$origdest,
|
||||
$ratelimit,
|
||||
$user,
|
||||
$mark,
|
||||
$connlimit,
|
||||
$time,
|
||||
$headers,
|
||||
$condition,
|
||||
$helper,
|
||||
$wildcard );
|
||||
|
||||
$macro_nest_level--;
|
||||
|
||||
return $generated;
|
||||
}
|
||||
#
|
||||
# Generate Fixed part of the rule
|
||||
#
|
||||
|
@ -7,6 +7,6 @@
|
||||
#
|
||||
# Please see http://shorewall.net/Actions.html for additional information.
|
||||
#
|
||||
###############################################################################
|
||||
#ACTION COMMENT (place '# ' below the 'C' in comment followed by
|
||||
# a comment describing the action)
|
||||
####################################################################################
|
||||
#ACTION OPTIONS COMMENT (place '# ' below the 'C' in comment followed by
|
||||
# v a comment describing the action)
|
||||
|
@ -8,5 +8,6 @@
|
||||
# Please see http://shorewall.net/Actions.html for additional information.
|
||||
#
|
||||
###############################################################################
|
||||
#ACTION COMMENT (place '# ' below the 'C' in comment followed by
|
||||
# v a comment describing the action)
|
||||
####################################################################################
|
||||
#ACTION OPTIONS COMMENT (place '# ' below the 'C' in comment followed by
|
||||
# v a comment describing the action)
|
||||
|
Loading…
Reference in New Issue
Block a user