diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index 735717607..05071a7da 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -1169,14 +1169,16 @@ sub finish_section ( $ ) { # # Create a normalized action name from the passed pieces. # -# Internally, action invocations are uniquely identified by a 4-tuple that -# includes the action name, log level, log tag and params. The pieces of the tuple -# are separated by ":". +# Internally, action invocations are uniquely identified by a 5-tuple that +# includes the action name, log level, log tag, dynamic invocation number +# (which is zero except for dynamic actions) and params. The pieces of the +# tuple are separated by ":". # sub normalize_action( $$$ ) { - my $action = shift; - my $level = shift; - my $param = shift; + my $action = shift; + my $level = shift; + my $param = shift; + my $dynamic = $actions{$action}->{dynamic}; ( $level, my $tag ) = split ':', $level; @@ -1185,7 +1187,9 @@ sub normalize_action( $$$ ) { $param = '' unless defined $param; $param = '' if $param eq '-'; - join( ':', $action, $level, $tag, $param ); + $actions{$action}->{dynamic}++ if $dynamic; + + join( ':', $action, $level, $tag, $dynamic, $param ); } # @@ -1203,9 +1207,9 @@ sub normalize_action_name( $ ) { # Produce a recognizable target from a normalized action # sub external_name( $ ) { - my ( $target, $level, $tag, $params ) = split /:/, shift, 4; + my ( $target, $level, $tag, $dynamic, $params ) = split /:/, shift, 5; - $target = join( '', $target, '(', $params , ')' ) if $params; + $target = join( '', $target, '(', $params , ')' ) if supplied $params; $target .= ":$level" if $level && $level ne 'none'; $target .= ":$tag" if $tag; $target; @@ -1214,13 +1218,13 @@ sub external_name( $ ) { # # Define an Action # -sub new_action( $$$$ ) { +sub new_action( $$$$$ ) { - my ( $action , $type, $noinline, $nolog ) = @_; + my ( $action , $type, $noinline, $nolog, $dynamic ) = @_; fatal_error "Invalid action name($action)" if reserved_name( $action ); - $actions{$action} = { actchain => '' , noinline => $noinline, nolog => $nolog } if $type & ACTION; + $actions{$action} = { actchain => '' , noinline => $noinline, nolog => $nolog , dynamic => $dynamic } if $type & ACTION; $targets{$action} = $type; } @@ -1693,7 +1697,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$$ ); sub process_action($$) { my ( $chainref, $caller ) = @_; my $wholeaction = $chainref->{action}; - my ( $action, $level, $tag, $param ) = split /:/, $wholeaction, 4; + my ( $action, $level, $tag, $dynamic, $param ) = split /:/, $wholeaction, 5; if ( $targets{$action} & BUILTIN ) { $level = '' if $level =~ /none!?/; @@ -1792,7 +1796,7 @@ sub process_actions() { # # Add built-in actions to the target table and create those actions # - $targets{$_} = new_action( $_ , ACTION + BUILTIN, 1, 0 ) for @builtins; + $targets{$_} = new_action( $_ , ACTION + BUILTIN, 1, 0 , 0 ) for @builtins; for my $file ( qw/actions.std actions/ ) { open_file( $file, 2 ); @@ -1815,6 +1819,7 @@ sub process_actions() { FILTER_OPT => 64 , NAT_OPT => 128 , TERMINATING_OPT => 256 , + DYNAMIC_OPT => 512 , }; my %options = ( inline => INLINE_OPT , @@ -1826,6 +1831,7 @@ sub process_actions() { filter => FILTER_OPT , nat => NAT_OPT , terminating => TERMINATING_OPT , + dynamic => DYNAMIC_OPT , ); my $opts = $type == INLINE ? NOLOG_OPT : 0; @@ -1881,17 +1887,25 @@ sub process_actions() { $targets{$action} = $actiontype; - make_terminating( $action ) if $opts & TERMINATING_OPT + make_terminating( $action ) if $opts & TERMINATING_OPT; + warning_message "The 'dynamic' option is ignored on built-in actions" if $opts & DYNAMIC_OPT; } else { fatal_error "Table names are only allowed for builtin actions" if $opts & ( MANGLE_OPT | RAW_OPT | NAT_OPT | FILTER_OPT ); - new_action $action, $type, ( $opts & NOINLINE_OPT ) != 0 , ( $opts & NOLOG_OPT ) != 0; + new_action( $action, + $type, + ( $opts & NOINLINE_OPT ) != 0, + ( $opts & NOLOG_OPT ) != 0, + ( $opts & DYNAMIC_OPT ) != 0 ); my $actionfile = find_file( "action.$action" ); fatal_error "Missing Action File ($actionfile)" unless -f $actionfile; - $inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT } if $type == INLINE; + if ( $type == INLINE ) { + warning_message "The 'dynamic' option is ignored on 'inline' actions" if $opts & DYNAMIC_OPT; + $inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT }; + } } } } diff --git a/Shorewall/manpages/shorewall-actions.xml b/Shorewall/manpages/shorewall-actions.xml index fe067d7c2..cc30cec77 100644 --- a/Shorewall/manpages/shorewall-actions.xml +++ b/Shorewall/manpages/shorewall-actions.xml @@ -85,6 +85,17 @@ + + dynamic + + + Added in Shorewall 5.0.4. When specified, this option + causes each invocation of the action to create a separate + iptables chain to hold the action rules. This is useful when + @caller is used within the action body. + + + inline diff --git a/Shorewall6/manpages/shorewall6-actions.xml b/Shorewall6/manpages/shorewall6-actions.xml index 7c9274a90..2e3a0ed03 100644 --- a/Shorewall6/manpages/shorewall6-actions.xml +++ b/Shorewall6/manpages/shorewall6-actions.xml @@ -86,6 +86,17 @@ + + dynamic + + + Added in Shorewall 5.0.4. When specified, this option + causes each invocation of the action to create a separate + ip6tables chain to hold the action rules. This is useful when + @caller is used within the action body. + + + inline