diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm
index 19eea6040..d7cde0ee7 100644
--- a/Shorewall/Perl/Shorewall/Chains.pm
+++ b/Shorewall/Perl/Shorewall/Chains.pm
@@ -337,6 +337,10 @@ our $VERSION = 'MODULEVERSION';
# complete => The last rule in the chain is a -g or a simple -j to a terminating target
# Suppresses adding additional rules to the chain end of the chain
# sections => { = 1, ... } - Records sections that have been completed.
+# chainnumber => Numeric enumeration of the builtin chains (mangle table only).
+# allowedchains
+# => Mangle action chains only -- specifies the set of builtin chains where
+# this action may be used.
# } ,
# => ...
# }
@@ -3023,6 +3027,7 @@ sub initialize_chain_table($) {
for my $chain ( qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT';
}
+
}
my $chainref;
@@ -3037,6 +3042,12 @@ sub initialize_chain_table($) {
$chainref = new_nat_chain( $globals{POSTROUTING} = 'SHOREWALL' );
set_optflags( $chainref, DONT_OPTIMIZE | DONT_DELETE | DONT_MOVE );
}
+
+ $mangle_table->{PREROUTING}{chainnumber} = PREROUTING;
+ $mangle_table->{INPUT}{chainnumber} = INPUT;
+ $mangle_table->{OUTPUT}{chainnumber} = OUTPUT;
+ $mangle_table->{FORWARD}{chainnumber} = FORWARD;
+ $mangle_table->{POSTROUTING}{chainnumber} = POSTROUTING;
}
if ( my $docker = $config{DOCKER} ) {
@@ -4505,7 +4516,7 @@ sub clearrule() {
sub state_match( $ ) {
my $state = shift;
- if ( $state eq 'ALL' ) {
+ if ( $state eq 'ALL' || $state eq '-' ) {
''
} else {
have_capability( 'CONNTRACK_MATCH' ) ? ( "-m conntrack --ctstate $state " ) : ( "-m state --state $state " );
diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm
index 4601f66e6..6f63b8f9c 100644
--- a/Shorewall/Perl/Shorewall/Rules.pm
+++ b/Shorewall/Perl/Shorewall/Rules.pm
@@ -63,7 +63,6 @@ our @EXPORT_OK = qw( initialize process_rule );
our %EXPORT_TAGS = ( Traffic => [ qw( process_tc_rule
process_mangle_rule
- convert_tos
%classids
%tcdevices
@@ -2124,10 +2123,7 @@ sub process_actions() {
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
- if ( $type & INLINE ) {
- fatal_error "Mangle actions may not be inlined" if $type & MANGLE_TABLE;
- $inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT };
- }
+ $inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT } if $type & INLINE;
}
}
}
@@ -3707,14 +3703,134 @@ sub process_rules() {
$section = $next_section = DEFAULTACTION_SECTION;
}
+sub process_mangle_inline( $$$$$$$$$$$$$$$$$$$ ) {
+ my ($inline, $chainref, $params, $source, $dest, $protos, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper, $headers, $probability , $dscp , $state, $time ) = @_;
+
+ my $oldparms = push_action_params( $inline,
+ $chainref,
+ $params,
+ 'none',
+ '' ,
+ $chainref->{name} );
+
+ my $inlinefile = $inlines{$inline}{file};
+
+ progress_message "..Expanding inline action $inlinefile...";
+
+ push_open $inlinefile, 2, 1, undef , 2;
+
+ my $save_comment = push_comment;
+
+ while ( read_a_line( NORMAL_READ ) ) {
+ my ( $moriginalmark, $msource, $mdest, $mprotos, $mports, $msports, $muser, $mtestval, $mlength, $mtos , $mconnbytes, $mhelper, $mheaders, $mprobability , $mdscp , $mstate, $mtime );
+ if ( $family == F_IPV4 ) {
+ ( $moriginalmark, $msource, $mdest, $mprotos, $mports, $msports, $muser, $mtestval, $mlength, $mtos , $mconnbytes, $mhelper, $mprobability, $mdscp, $mstate, $mtime ) =
+ split_line2( 'mangle file',
+ { mark => 0,
+ action => 0,
+ source => 1,
+ dest => 2,
+ proto => 3,
+ dport => 4,
+ sport => 5,
+ user => 6,
+ test => 7,
+ length => 8,
+ tos => 9,
+ connbytes => 10,
+ helper => 11,
+ probability => 12 ,
+ scp => 13,
+ state => 14,
+ time => 15,
+ },
+ {},
+ 16,
+ 1 );
+ $headers = $mheaders = '-';
+ } else {
+ ( $moriginalmark, $msource, $mdest, $mprotos, $mports, $msports, $muser, $mtestval, $mlength, $mtos , $mconnbytes, $mhelper, $mheaders, $mprobability, $mdscp, $mstate, $mtime ) =
+ split_line2( 'mangle file',
+ { mark => 0,
+ action => 0,
+ source => 1,
+ dest => 2,
+ proto => 3,
+ dport => 4,
+ sport => 5,
+ user => 6,
+ test => 7,
+ length => 8,
+ tos => 9,
+ connbytes => 10,
+ helper => 11,
+ headers => 12,
+ probability => 13,
+ dscp => 14,
+ state => 15,
+ time => 16,
+ },
+ {},
+ 17,
+ 1 );
+ }
+
+ fatal_error 'ACTION must be specified' if $moriginalmark eq '-';
+
+ if ( $moriginalmark eq 'DEFAULTS' ) {
+ default_action_params( $chainref, split_list( $msource, 'defaults' ) );
+ next;
+ }
+
+ $msource = $source if $msource eq '-';
+ $mdest = $dest if $msource eq '-';
+ $mprotos = $protos if $mprotos eq '-';
+
+ for my $proto (split_list( $mprotos, 'Protocol' ) ) {
+ process_mangle_rule1( $chainref,
+ $moriginalmark,
+ $msource,
+ $dest,
+ $proto,
+ merge_macro_column( $mports, $ports ),
+ merge_macro_column( $msports, $sports ),
+ merge_macro_column( $muser, $muser ),
+ merge_macro_column( $mtestval, $testval ),
+ merge_macro_column( $mlength, $length ),
+ merge_macro_column( $mtos , $tos ),
+ merge_macro_column( $mconnbytes, $connbytes ),
+ merge_macro_column( $mhelper, $helper ),
+ merge_macro_column( $mheaders, $headers ),
+ merge_macro_column( $mprobability , $probability ),
+ merge_macro_column( $mdscp , $dscp ),
+ merge_macro_column( $mstate, $state ),
+ merge_macro_column( $mtime, $time ) );
+ }
+
+ progress_message " Rule \"$currentline\" $done";
+ }
+
+ pop_comment( $save_comment );
+
+ pop_open;
+
+ progress_message "..End inline action $inlinefile";
+
+ pop_action_params( $oldparms );
+}
+
################################################################################
# Code moved from the Tc module in Shorewall 5.0.7 #
################################################################################
#
-# Process a rule from the mangle file
+# Process a rule from the mangle file. When the target is an action name, this
+# function will be called recursively for each rule in the action body. Recursive
+# calls pass a chain reference in the first argument and the generated rule is
+# appended to that chain. The chain with be the action's chain unless the action
+# is inlined, in which case it will be the chain which invoked the action.
#
sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
- my ( $chainref, $action, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper, $headers, $probability , $dscp , $state, $time ) = @_;
+ my ( $chainref, $action, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper, $headers, $probability , $dscp , $state, $time) = @_;
my %designators = (
P => PREROUTING,
@@ -3741,7 +3857,8 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
128 => 'PREROUTING',
);
- my $inaction = defined $chainref;
+ my $inchain = defined $chainref;
+ my $inaction;
my $target = '';
my $junk = '';
my $raw_matches = '';
@@ -3760,7 +3877,12 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
my $usergenerated;
my $actiontype;
my $commandref;
-
+ #
+ # Subroutine for handling MARK and CONNMARK. We use an enclosure so as to keep visibility of the
+ # function's local variables without making them static. process_mangle_rule1() is called
+ # recursively, so static (our) variables cannot be used unless they are saved/restored during
+ # recursion.
+ #
my $handle_mark_param = sub( ) {
my ( $option, $marktype ) = @_;
my $and_or = $params =~ s/^([|&])// ? $1 : '';
@@ -3867,7 +3989,9 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
}
}
};
-
+ #
+ # Subroutine to handle ADD and DEL rules
+ #
my $ipset_command = sub () {
my %xlate = ( ADD => 'add-set' , DEL => 'del-set' );
@@ -4315,7 +4439,9 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
},
},
);
-
+ #
+ # Subroutine for handling normal actions
+ #
my $actionref = {
defaultchain => 0,
allowedchains => ALLCHAINS ,
@@ -4352,14 +4478,59 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
}
};
#
+ # Subroutine to resolve which chain to use
+ #
+ my $resolve_chain = sub() {
+ $chain ||= $designator;
+ $chain ||= $commandref->{defaultchain};
+ $chain ||= $default_chain;
+ $chainref = ensure_chain( 'mangle', $chainnames{$chain} );
+ };
+ #
+ #
+ # Subroutine for handling inline actions
+ #
+ my $inlineref = {
+ defaultchain => 0,
+ allowedchains => ALLCHAINS ,
+ minparams => 0 ,
+ maxparams => 16 ,
+ function => sub() {
+ fatal_error( qq(Action $cmd may not be used in the mangle file) ) unless $actiontype & MANGLE_TABLE;
+
+ $resolve_chain->() unless $inchain;
+
+ process_mangle_inline( $cmd,
+ $chainref,
+ $params,
+ $source,
+ $dest,
+ $proto,
+ $ports,
+ $sports,
+ $user,
+ $testval,
+ $length,
+ $tos ,
+ $connbytes,
+ $helper,
+ $headers,
+ $probability ,
+ $dscp ,
+ $state,
+ $time );
+ $done = 1;
+ }
+ };
+ #
# Function Body
#
- if ( $inaction ) {
- assert( $chainref->{action} );
+ if ( $inchain ) {
+ ( $inaction, undef, undef, undef ) = split /:/, $chainref->{action}, 4 if $chainref->{action};
#
# Set chain type
#
- $chain = ACTIONCHAIN;
+ $chain = $chainref->{chainnumber} || ACTIONCHAIN;
}
( $cmd, $designator ) = split_action( $action );
@@ -4375,11 +4546,14 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$actiontype = $builtin_target{$cmd} || $targets{$cmd} || 0;
- $commandref = $commands{$cmd};
-
- unless ( $commandref ) {
- fatal_error "Invalid ACTION ($cmd)" unless $actiontype & ACTION;
- $commandref = $actionref;
+ unless ( $commandref = $commands{$cmd} ) {
+ if ( $actiontype & ACTION ) {
+ $commandref = $actionref;
+ } elsif ( $actiontype & INLINE ) {
+ $commandref = $inlineref;
+ } else {
+ fatal_error "Invalid ACTION ($cmd)";
+ }
}
if ( $cmd eq 'INLINE' ) {
@@ -4444,8 +4618,6 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
fatal_error "Invalid STATE ($_)" unless exists $state{$_};
fatal_error "Duplicate STATE ($_)" if $state{$_}++;
}
- } else {
- $state = 'ALL';
}
#
# Call the command's processing function
@@ -4453,14 +4625,15 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$commandref->{function}->();
unless ( $done ) {
- $chain ||= $designator;
- $chain ||= $commandref->{defaultchain};
- $chain ||= $default_chain;
-
- if ( $inaction ) {
- fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chainref->{allowedchains};;
- $chainref->{allowedchains} &= $commandref->{allowedchains};
+ if ( $inchain ) {
+ if ( $chain == ACTIONCHAIN ) {
+ fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chainref->{allowedchains};
+ $chainref->{allowedchains} &= $commandref->{allowedchains};
+ } else {
+ fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain;
+ }
} else {
+ $resolve_chain->();
fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain;
$chainref = ensure_chain( 'mangle', $chainnames{$chain} );
}
diff --git a/Shorewall/manpages/shorewall-actions.xml b/Shorewall/manpages/shorewall-actions.xml
index fe067d7c2..e4bc14964 100644
--- a/Shorewall/manpages/shorewall-actions.xml
+++ b/Shorewall/manpages/shorewall-actions.xml
@@ -118,6 +118,18 @@
+
+ mangle
+
+
+ Added in Shorewall 5.0.7. Specifies that this action is
+ to be used in shorewall-mangle(5) rather
+ than shorewall-rules(5).
+
+
+
noinline
diff --git a/Shorewall/manpages/shorewall-mangle.xml b/Shorewall/manpages/shorewall-mangle.xml
index 9c3d7ff66..084108419 100644
--- a/Shorewall/manpages/shorewall-mangle.xml
+++ b/Shorewall/manpages/shorewall-mangle.xml
@@ -68,8 +68,9 @@
command[(parameters)][:chain-designator]
- The chain-specifier indicates the Netfilter chain that the
- entry applies to and may be one of the following:
+ The chain-designator indicates the
+ Netfilter chain that the entry applies to and may be one of the
+ following:
@@ -111,10 +112,14 @@
url="/manpages/shorewall.conf.html">shorewall.conf(5), and
FORWARD when MARK_IN_FORWARD_CHAIN=Yes.
- A chain-designator may not be specified if the SOURCE or DEST
- columns begin with '$FW'. When the SOURCE is $FW, the generated rule
- is always placed in the OUTPUT chain. If DEST is '$FW', then the
- rule is placed in the INPUT chain.
+ A chain-designator may not be
+ specified if the SOURCE or DEST columns begin with '$FW'. When the
+ SOURCE is $FW, the generated rule is always placed in the OUTPUT
+ chain. If DEST is '$FW', then the rule is placed in the INPUT chain.
+ Additionally, a chain-designator may not
+ be specified in an action body unless the action is declared as
+ in shorewall-actions(5).Where a command takes parameters, those parameters are
enclosed in parentheses ("(....)") and separated by commas.
diff --git a/Shorewall6/manpages/shorewall6-actions.xml b/Shorewall6/manpages/shorewall6-actions.xml
index 7c9274a90..92d086dab 100644
--- a/Shorewall6/manpages/shorewall6-actions.xml
+++ b/Shorewall6/manpages/shorewall6-actions.xml
@@ -119,6 +119,18 @@
+
+ mangle
+
+
+ Added in Shorewall 5.0.7. Specifies that this action is
+ to be used in shorewall6-mangle(5)
+ rather than shorewall6-rules(5).
+
+
+
noinline
diff --git a/Shorewall6/manpages/shorewall6-mangle.xml b/Shorewall6/manpages/shorewall6-mangle.xml
index 4ea9b1d2c..34fe0d1e0 100644
--- a/Shorewall6/manpages/shorewall6-mangle.xml
+++ b/Shorewall6/manpages/shorewall6-mangle.xml
@@ -69,8 +69,9 @@
command[(parameters)][:chain-designator]
- The chain-specifier indicates the Netfilter chain that the
- entry applies to and may be one of the following:
+ The chain-designator indicates the
+ Netfilter chain that the entry applies to and may be one of the
+ following:
@@ -112,10 +113,14 @@
url="/manpages6/shorewall6.conf.html">shorewall6.conf(5),
and FORWARD when MARK_IN_FORWARD_CHAIN=Yes.
- A chain-designator may not be specified if the SOURCE or DEST
- columns begin with '$FW'. When the SOURCE is $FW, the generated rule
- is always placed in the OUTPUT chain. If DEST is '$FW', then the
- rule is placed in the INPUT chain.
+ A chain-designator may not be
+ specified if the SOURCE or DEST columns begin with '$FW'. When the
+ SOURCE is $FW, the generated rule is always placed in the OUTPUT
+ chain. If DEST is '$FW', then the rule is placed in the INPUT chain.
+ Additionally, a chain-designator may not
+ be specified in an action body unless the action is declared as
+ in shorewall6-actions(5).Where a command takes parameters, those parameters are
enclosed in parentheses ("(....)") and separated by commas.
diff --git a/docs/Actions.xml b/docs/Actions.xml
index b6471ef63..0a9c7eefb 100644
--- a/docs/Actions.xml
+++ b/docs/Actions.xml
@@ -32,6 +32,8 @@
2013
+ 2015-2016
+
Thomas M. Eastep
@@ -397,6 +399,27 @@ REDIRECT net - tcp 80 - 1.2.3.4
url="configuration_file_basics.htm#ActionVariables">Action Variables
section of the Configuration Basics article.
+
+
+ Mangle Actions
+
+ Beginning with Shorewall 5.0.7, actions may be used in shorewall-mangle(5) and
+ shorewall6-mangle(5).
+ Because the rules and mangle files have different column layouts,
+ actions can be defined to be used in one file or the other but not in
+ both. To designate an action to be used in the mangle file, specify the
+ option in the action's entry in shorewall-actions(5) or
+ shorewall6-actions(5).
+
+ To create a mangle action, follow the steps in the preceding
+ section, but use the
+ /usr/share/shorewall/action.mangletemplate file.
+
+