Inline mangle actions

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2016-03-09 10:28:02 -08:00
parent 991d8d2d3f
commit ec9148637f
7 changed files with 282 additions and 41 deletions

View File

@ -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 # 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 # Suppresses adding additional rules to the chain end of the chain
# sections => { <section> = 1, ... } - Records sections that have been completed. # sections => { <section> = 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.
# } , # } ,
# <chain2> => ... # <chain2> => ...
# } # }
@ -3023,6 +3027,7 @@ sub initialize_chain_table($) {
for my $chain ( qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) ) { for my $chain ( qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT'; new_builtin_chain 'mangle', $chain, 'ACCEPT';
} }
} }
my $chainref; my $chainref;
@ -3037,6 +3042,12 @@ sub initialize_chain_table($) {
$chainref = new_nat_chain( $globals{POSTROUTING} = 'SHOREWALL' ); $chainref = new_nat_chain( $globals{POSTROUTING} = 'SHOREWALL' );
set_optflags( $chainref, DONT_OPTIMIZE | DONT_DELETE | DONT_MOVE ); 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} ) { if ( my $docker = $config{DOCKER} ) {
@ -4505,7 +4516,7 @@ sub clearrule() {
sub state_match( $ ) { sub state_match( $ ) {
my $state = shift; my $state = shift;
if ( $state eq 'ALL' ) { if ( $state eq 'ALL' || $state eq '-' ) {
'' ''
} else { } else {
have_capability( 'CONNTRACK_MATCH' ) ? ( "-m conntrack --ctstate $state " ) : ( "-m state --state $state " ); have_capability( 'CONNTRACK_MATCH' ) ? ( "-m conntrack --ctstate $state " ) : ( "-m state --state $state " );

View File

@ -63,7 +63,6 @@ our @EXPORT_OK = qw( initialize process_rule );
our %EXPORT_TAGS = ( Traffic => [ qw( process_tc_rule our %EXPORT_TAGS = ( Traffic => [ qw( process_tc_rule
process_mangle_rule process_mangle_rule
convert_tos
%classids %classids
%tcdevices %tcdevices
@ -2124,10 +2123,7 @@ sub process_actions() {
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile; fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
if ( $type & INLINE ) { $inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT } if $type & INLINE;
fatal_error "Mangle actions may not be inlined" if $type & MANGLE_TABLE;
$inlines{$action} = { file => $actionfile, nolog => $opts & NOLOG_OPT };
}
} }
} }
} }
@ -3707,14 +3703,134 @@ sub process_rules() {
$section = $next_section = DEFAULTACTION_SECTION; $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 # # 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( $$$$$$$$$$$$$$$$$$ ) { 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 = ( my %designators = (
P => PREROUTING, P => PREROUTING,
@ -3741,7 +3857,8 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
128 => 'PREROUTING', 128 => 'PREROUTING',
); );
my $inaction = defined $chainref; my $inchain = defined $chainref;
my $inaction;
my $target = ''; my $target = '';
my $junk = ''; my $junk = '';
my $raw_matches = ''; my $raw_matches = '';
@ -3760,7 +3877,12 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
my $usergenerated; my $usergenerated;
my $actiontype; my $actiontype;
my $commandref; 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 $handle_mark_param = sub( ) {
my ( $option, $marktype ) = @_; my ( $option, $marktype ) = @_;
my $and_or = $params =~ s/^([|&])// ? $1 : ''; 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 $ipset_command = sub () {
my %xlate = ( ADD => 'add-set' , DEL => 'del-set' ); my %xlate = ( ADD => 'add-set' , DEL => 'del-set' );
@ -4315,7 +4439,9 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
}, },
}, },
); );
#
# Subroutine for handling normal actions
#
my $actionref = { my $actionref = {
defaultchain => 0, defaultchain => 0,
allowedchains => ALLCHAINS , 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 # Function Body
# #
if ( $inaction ) { if ( $inchain ) {
assert( $chainref->{action} ); ( $inaction, undef, undef, undef ) = split /:/, $chainref->{action}, 4 if $chainref->{action};
# #
# Set chain type # Set chain type
# #
$chain = ACTIONCHAIN; $chain = $chainref->{chainnumber} || ACTIONCHAIN;
} }
( $cmd, $designator ) = split_action( $action ); ( $cmd, $designator ) = split_action( $action );
@ -4375,11 +4546,14 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$actiontype = $builtin_target{$cmd} || $targets{$cmd} || 0; $actiontype = $builtin_target{$cmd} || $targets{$cmd} || 0;
$commandref = $commands{$cmd}; unless ( $commandref = $commands{$cmd} ) {
if ( $actiontype & ACTION ) {
unless ( $commandref ) { $commandref = $actionref;
fatal_error "Invalid ACTION ($cmd)" unless $actiontype & ACTION; } elsif ( $actiontype & INLINE ) {
$commandref = $actionref; $commandref = $inlineref;
} else {
fatal_error "Invalid ACTION ($cmd)";
}
} }
if ( $cmd eq 'INLINE' ) { if ( $cmd eq 'INLINE' ) {
@ -4444,8 +4618,6 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
fatal_error "Invalid STATE ($_)" unless exists $state{$_}; fatal_error "Invalid STATE ($_)" unless exists $state{$_};
fatal_error "Duplicate STATE ($_)" if $state{$_}++; fatal_error "Duplicate STATE ($_)" if $state{$_}++;
} }
} else {
$state = 'ALL';
} }
# #
# Call the command's processing function # Call the command's processing function
@ -4453,14 +4625,15 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$commandref->{function}->(); $commandref->{function}->();
unless ( $done ) { unless ( $done ) {
$chain ||= $designator; if ( $inchain ) {
$chain ||= $commandref->{defaultchain}; if ( $chain == ACTIONCHAIN ) {
$chain ||= $default_chain; fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chainref->{allowedchains};
$chainref->{allowedchains} &= $commandref->{allowedchains};
if ( $inaction ) { } else {
fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chainref->{allowedchains};; fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain;
$chainref->{allowedchains} &= $commandref->{allowedchains}; }
} else { } else {
$resolve_chain->();
fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain; fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain;
$chainref = ensure_chain( 'mangle', $chainnames{$chain} ); $chainref = ensure_chain( 'mangle', $chainnames{$chain} );
} }

View File

@ -118,6 +118,18 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>mangle</term>
<listitem>
<para>Added in Shorewall 5.0.7. Specifies that this action is
to be used in <ulink
url="shorewall-mangle.html">shorewall-mangle(5)</ulink> rather
than <ulink
url="shorewall-rules.html">shorewall-rules(5)</ulink>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term>noinline</term> <term>noinline</term>

View File

@ -68,8 +68,9 @@
<replaceable>command</replaceable>[(<replaceable>parameters</replaceable>)][:<replaceable>chain-designator</replaceable>]</term> <replaceable>command</replaceable>[(<replaceable>parameters</replaceable>)][:<replaceable>chain-designator</replaceable>]</term>
<listitem> <listitem>
<para>The chain-specifier indicates the Netfilter chain that the <para>The <replaceable>chain-designator </replaceable>indicates the
entry applies to and may be one of the following:</para> Netfilter chain that the entry applies to and may be one of the
following:</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
@ -111,10 +112,14 @@
url="/manpages/shorewall.conf.html">shorewall.conf(5)</ulink>, and url="/manpages/shorewall.conf.html">shorewall.conf(5)</ulink>, and
FORWARD when MARK_IN_FORWARD_CHAIN=Yes.</para> FORWARD when MARK_IN_FORWARD_CHAIN=Yes.</para>
<para>A chain-designator may not be specified if the SOURCE or DEST <para>A <replaceable>chain-designator</replaceable> may not be
columns begin with '$FW'. When the SOURCE is $FW, the generated rule specified if the SOURCE or DEST columns begin with '$FW'. When the
is always placed in the OUTPUT chain. If DEST is '$FW', then the SOURCE is $FW, the generated rule is always placed in the OUTPUT
rule is placed in the INPUT chain.</para> chain. If DEST is '$FW', then the rule is placed in the INPUT chain.
Additionally, a <replaceable>chain-designator</replaceable> may not
be specified in an action body unless the action is declared as
<option>inline</option> in <ulink
url="shorewall6-actions.html">shorewall-actions</ulink>(5).</para>
<para>Where a command takes parameters, those parameters are <para>Where a command takes parameters, those parameters are
enclosed in parentheses ("(....)") and separated by commas.</para> enclosed in parentheses ("(....)") and separated by commas.</para>

View File

@ -119,6 +119,18 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>mangle</term>
<listitem>
<para>Added in Shorewall 5.0.7. Specifies that this action is
to be used in <ulink
url="shorewall6-mangle.html">shorewall6-mangle(5)</ulink>
rather than <ulink
url="shorewall6-rules.html">shorewall6-rules(5)</ulink>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term>noinline</term> <term>noinline</term>

View File

@ -69,8 +69,9 @@
<replaceable>command</replaceable>[(<replaceable>parameters</replaceable>)][:<replaceable>chain-designator</replaceable>]</term> <replaceable>command</replaceable>[(<replaceable>parameters</replaceable>)][:<replaceable>chain-designator</replaceable>]</term>
<listitem> <listitem>
<para>The chain-specifier indicates the Netfilter chain that the <para>The <replaceable>chain-designator</replaceable> indicates the
entry applies to and may be one of the following:</para> Netfilter chain that the entry applies to and may be one of the
following:</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
@ -112,10 +113,14 @@
url="/manpages6/shorewall6.conf.html">shorewall6.conf(5)</ulink>, url="/manpages6/shorewall6.conf.html">shorewall6.conf(5)</ulink>,
and FORWARD when MARK_IN_FORWARD_CHAIN=Yes.</para> and FORWARD when MARK_IN_FORWARD_CHAIN=Yes.</para>
<para>A chain-designator may not be specified if the SOURCE or DEST <para>A <replaceable>chain-designator</replaceable> may not be
columns begin with '$FW'. When the SOURCE is $FW, the generated rule specified if the SOURCE or DEST columns begin with '$FW'. When the
is always placed in the OUTPUT chain. If DEST is '$FW', then the SOURCE is $FW, the generated rule is always placed in the OUTPUT
rule is placed in the INPUT chain.</para> chain. If DEST is '$FW', then the rule is placed in the INPUT chain.
Additionally, a <replaceable>chain-designator</replaceable> may not
be specified in an action body unless the action is declared as
<option>inline</option> in <ulink
url="shorewall6-actions.html">shorewall6-actions</ulink>(5).</para>
<para>Where a command takes parameters, those parameters are <para>Where a command takes parameters, those parameters are
enclosed in parentheses ("(....)") and separated by commas.</para> enclosed in parentheses ("(....)") and separated by commas.</para>

View File

@ -32,6 +32,8 @@
<year>2013</year> <year>2013</year>
<year>2015-2016</year>
<holder>Thomas M. Eastep</holder> <holder>Thomas M. Eastep</holder>
</copyright> </copyright>
@ -397,6 +399,27 @@ REDIRECT net - tcp 80 - 1.2.3.4</programlisting>
url="configuration_file_basics.htm#ActionVariables">Action Variables url="configuration_file_basics.htm#ActionVariables">Action Variables
section</ulink> of the Configuration Basics article.</para> section</ulink> of the Configuration Basics article.</para>
</section> </section>
<section>
<title>Mangle Actions</title>
<para>Beginning with Shorewall 5.0.7, actions may be used in <ulink
url="manpages/shorewall-mangle.html">shorewall-mangle(5)</ulink> and
<ulink
url="manpages6/shorewall6-mangle.html">shorewall6-mangle(5)</ulink>.
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>mangle</option> option in the action's entry in <ulink
url="manpages/shorewall-actions.html">shorewall-actions</ulink>(5) or
<ulink
url="manpages6/shorewall6-actions.html">shorewall6-actions</ulink>(5).</para>
<para>To create a mangle action, follow the steps in the preceding
section, but use the
<filename>/usr/share/shorewall/action.mangletemplate</filename> file.
</para>
</section>
</section> </section>
<section id="Logging"> <section id="Logging">