More Mangle Action Changes

- Move open_mangle_for_output() back to the Tc module
- Eliminate global variables in process_mangle_rule1()
- Allow creation of mangle action chains
- Minor (but needed) logic changes

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2016-03-07 13:51:28 -08:00
parent bbbf54f7c3
commit 81c16d2d67
4 changed files with 151 additions and 122 deletions

View File

@ -59,21 +59,21 @@ our $acctable;
# #
use constant { use constant {
LEGACY => 0, LEGACY_SECTION => 0,
PREROUTING => 1, PREROUTING_SECTION => 1,
INPUT => 2, INPUT_SECTION => 2,
OUTPUT => 3, OUTPUT_SECTION => 3,
FORWARD => 4, FORWARD_SECTION => 4,
POSTROUTING => 5 POSTROUTING_SECTION => 5
}; };
# #
# Map names to values # Map names to values
# #
our %asections = ( PREROUTING => PREROUTING, our %asections = ( PREROUTING => PREROUTING_SECTION,
INPUT => INPUT, INPUT => INPUT_SECTION,
FORWARD => FORWARD, FORWARD => FORWARD_SECTION,
OUTPUT => OUTPUT, OUTPUT => OUTPUT_SECTION,
POSTROUTING => POSTROUTING POSTROUTING => POSTROUTING_SECTION
); );
# #
@ -157,7 +157,7 @@ sub process_accounting_rule1( $$$$$$$$$$$ ) {
$jumpchainref = 0; $jumpchainref = 0;
$asection = LEGACY if $asection < 0; $asection = LEGACY_SECTION if $asection < 0;
our $disposition = ''; our $disposition = '';

View File

@ -138,6 +138,17 @@ our %EXPORT_TAGS = (
ALL_COMMANDS ALL_COMMANDS
NOT_RESTORE NOT_RESTORE
PREROUTING
INPUT
FORWARD
OUTPUT
POSTROUTING
ALLCHAINS
STICKY
STICKO
REALPREROUTING
ACTIONCHAIN
unreachable_warning unreachable_warning
state_match state_match
state_imatch state_imatch
@ -188,6 +199,7 @@ our %EXPORT_TAGS = (
ensure_raw_chain ensure_raw_chain
ensure_rawpost_chain ensure_rawpost_chain
new_standard_chain new_standard_chain
new_action_chain
new_builtin_chain new_builtin_chain
new_nat_chain new_nat_chain
optimize_chain optimize_chain
@ -456,6 +468,22 @@ use constant { NO_RESTRICT => 0, # FORWARD chain rule - Both -i an
ALL_RESTRICT => 12, # fw->fw rule - neither -i nor -o allowed ALL_RESTRICT => 12, # fw->fw rule - neither -i nor -o allowed
DESTIFACE_DISALLOW => 32, # Don't allow dest interface. Similar to INPUT_RESTRICT but generates a more relevant error message DESTIFACE_DISALLOW => 32, # Don't allow dest interface. Similar to INPUT_RESTRICT but generates a more relevant error message
}; };
#
# Mangle Table allowed chains enumeration
#
use constant {
PREROUTING => 1, #Actually tcpre
INPUT => 2, #Actually tcin
FORWARD => 4, #Actually tcfor
OUTPUT => 8, #Actually tcout
POSTROUTING => 16, #Actually tcpost
ALLCHAINS => 31,
STICKY => 32,
STICKO => 64,
REALPREROUTING => 128,
ACTIONCHAIN => 256,
};
# #
# Possible IPSET options # Possible IPSET options
# #
@ -2325,6 +2353,7 @@ sub new_chain($$)
filtered => 0, filtered => 0,
optflags => 0, optflags => 0,
origin => shortlineinfo( '' ), origin => shortlineinfo( '' ),
restriction => NO_RESTRICT,
}; };
trace( $chainref, 'N', undef, '' ) if $debug; trace( $chainref, 'N', undef, '' ) if $debug;
@ -2738,6 +2767,13 @@ sub new_standard_chain($) {
$chainref; $chainref;
} }
sub new_action_chain($$) {
my $chainref = &new_chain( @_ );
$chainref->{referenced} = 1;
$chainref->{allowedchains} = ALLCHAINS | REALPREROUTING | ACTIONCHAIN;
$chainref;
}
sub new_nat_chain($) { sub new_nat_chain($) {
my $chainref = new_chain 'nat' ,$_[0]; my $chainref = new_chain 'nat' ,$_[0];
$chainref->{referenced} = 1; $chainref->{referenced} = 1;

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
open_mangle_for_output
convert_tos convert_tos
%classids %classids
@ -1334,11 +1333,12 @@ sub new_action( $$$$ ) {
# this function truncates the original chain name where necessary before # this function truncates the original chain name where necessary before
# it adds the leading "%" and trailing sequence number. # it adds the leading "%" and trailing sequence number.
# #
sub createlogactionchain( $$$$$ ) { sub createlogactionchain( $$$$$$ ) {
my ( $normalized, $action, $level, $tag, $param ) = @_; my ( $table, $normalized, $action, $level, $tag, $param ) = @_;
my $chain = $action; my $chain = $action;
my $actionref = $actions{$action}; my $actionref = $actions{$action};
my $chainref; my $chainref;
my $tableref = $chain_table{$table};
validate_level $level; validate_level $level;
@ -1346,14 +1346,14 @@ sub createlogactionchain( $$$$$ ) {
$chain = substr $chain, 0, 28 if ( length $chain ) > 28; $chain = substr $chain, 0, 28 if ( length $chain ) > 28;
if ( $filter_table->{$chain} ) { if ( $tableref->{$chain} ) {
CHECKDUP: CHECKDUP:
{ {
$actionref->{actchain}++ while $chain_table{filter}{'%' . $chain . $actionref->{actchain}}; $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; $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}++; $usedactions{$normalized} = $chainref = new_action_chain( $table, '%' . $chain . $actionref->{actchain}++ );
fatal_error "Too many invocations of Action $action" if $actionref->{actchain} > 99; fatal_error "Too many invocations of Action $action" if $actionref->{actchain} > 99;
} else { } else {
@ -1386,13 +1386,13 @@ sub createlogactionchain( $$$$$ ) {
$chainref; $chainref;
} }
sub createsimpleactionchain( $ ) { sub createsimpleactionchain( $$ ) {
my $action = shift; my ( $table, $action ) = @_;
my $normalized = normalize_action_name( $action ); my $normalized = normalize_action_name( $action );
return createlogactionchain( $normalized, $action, 'none', '', '' ) if $filter_table->{$action} || $nat_table->{$action}; return createlogactionchain( $table, $normalized, $action, 'none', '', '' ) if $filter_table->{$action} || $nat_table->{$action};
my $chainref = new_standard_chain $action; my $chainref = new_action_chain( $table, $action );
$usedactions{$normalized} = $chainref; $usedactions{$normalized} = $chainref;
@ -1425,8 +1425,8 @@ sub createsimpleactionchain( $ ) {
# #
# Create an action chain and run its associated user exit # Create an action chain and run its associated user exit
# #
sub createactionchain( $ ) { sub createactionchain( $$ ) {
my $normalized = shift; my ( $table, $normalized ) = @_;
my ( $target, $level, $tag, $caller, $param ) = split /:/, $normalized, ACTION_TUPLE_ELEMENTS; my ( $target, $level, $tag, $caller, $param ) = split /:/, $normalized, ACTION_TUPLE_ELEMENTS;
@ -1435,9 +1435,9 @@ sub createactionchain( $ ) {
my $chainref; my $chainref;
if ( $level eq 'none' && $tag eq '' && $param eq '' ) { if ( $level eq 'none' && $tag eq '' && $param eq '' ) {
createsimpleactionchain $target; createsimpleactionchain($table, $target );
} else { } else {
createlogactionchain $normalized, $target , $level , $tag, $param; createlogactionchain( $table, $normalized, $target , $level , $tag, $param );
} }
} }
@ -1445,13 +1445,13 @@ sub createactionchain( $ ) {
# Mark an action as used and create its chain. Returns a reference to the chain if the chain was # Mark an action as used and create its chain. Returns a reference to the chain if the chain was
# created on this call or 0 otherwise. # created on this call or 0 otherwise.
# #
sub use_action( $ ) { sub use_action( $$ ) {
my $normalized = shift; my ( $table, $normalized ) = @_;
if ( $usedactions{$normalized} ) { if ( $usedactions{$normalized} ) {
0; 0;
} else { } else {
createactionchain $normalized; createactionchain( $table, $normalized );
} }
} }
@ -2145,7 +2145,7 @@ sub process_actions() {
sub use_policy_action( $$ ) { sub use_policy_action( $$ ) {
my ( $normalized_target, $caller ) = @_; my ( $normalized_target, $caller ) = @_;
my $ref = use_action( $normalized_target ); my $ref = use_action( 'filter', $normalized_target );
if ( $ref ) { if ( $ref ) {
process_action( $normalized_target, $ref, $caller ); process_action( $normalized_target, $ref, $caller );
@ -2910,7 +2910,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$$ ) {
fatal_error( "Action $basictarget invoked Recursively (" . join( '->', map( external_name( $_ ), @actionstack , $normalized_target ) ) . ')' ) if $active{$basictarget}; fatal_error( "Action $basictarget invoked Recursively (" . join( '->', map( external_name( $_ ), @actionstack , $normalized_target ) ) . ')' ) if $active{$basictarget};
if ( my $ref = use_action( $normalized_target ) ) { if ( my $ref = use_action( 'filter', $normalized_target ) ) {
# #
# First reference to this tuple # First reference to this tuple
# #
@ -3716,18 +3716,6 @@ sub process_rules() {
sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) { sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
our ( $chainref, $action, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper, $headers, $probability , $dscp , $state, $time ) = @_; our ( $chainref, $action, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper, $headers, $probability , $dscp , $state, $time ) = @_;
use constant {
PREROUTING => 1, #Actually tcpre
INPUT => 2, #Actually tcin
FORWARD => 4, #Actually tcfor
OUTPUT => 8, #Actually tcout
POSTROUTING => 16, #Actually tcpost
ALLCHAINS => 31,
STICKY => 32,
STICKO => 64,
REALPREROUTING => 128
};
my %designators = ( my %designators = (
P => PREROUTING, P => PREROUTING,
I => INPUT, I => INPUT,
@ -3735,42 +3723,43 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
O => OUTPUT, O => OUTPUT,
T => POSTROUTING ); T => POSTROUTING );
our %chainlabels = ( 1 => 'PREROUTING', my %chainlabels = ( 1 => 'PREROUTING',
2 => 'INPUT', 2 => 'INPUT',
4 => 'FORWARD', 4 => 'FORWARD',
8 => 'OUTPUT', 8 => 'OUTPUT',
16 => 'POSTROUTING' ); 16 => 'POSTROUTING' );
our %chainnames = ( 1 => 'tcpre', my %chainnames = ( 1 => 'tcpre',
2 => 'tcin', 2 => 'tcin',
4 => 'tcfor', 4 => 'tcfor',
8 => 'tcout', 8 => 'tcout',
16 => 'tcpost', 16 => 'tcpost',
32 => 'sticky', 32 => 'sticky',
64 => 'sticko', 64 => 'sticko',
128 => 'PREROUTING', 128 => 'PREROUTING',
); );
our $inaction = defined $chainref; my $inaction = defined $chainref;
our $target = ''; my $target = '';
my $junk = ''; my $junk = '';
our $raw_matches = ''; my $raw_matches = '';
our $chain = 0; my $chain = 0;
our $matches = ''; my $matches = '';
our $params = ''; my $params = '';
our $done = 0; my $done = 0;
our $default_chain = 0; my $default_chain = 0;
our $restriction = 0; my $restriction = NO_RESTRICT;
our $exceptionrule = ''; my $exceptionrule = '';
my $device = ''; my $device = '';
our $cmd; my $cmd;
our $designator; my $designator;
our $ttl = 0; my $ttl = 0;
my $fw = firewall_zone; my $fw = firewall_zone;
my $usergenerated; my $usergenerated;
my $actiontype; my $actiontype;
my $commandref;
sub handle_mark_param( $$ ) { my $handle_mark_param = sub( ) {
my ( $option, $marktype ) = @_; my ( $option, $marktype ) = @_;
my $and_or = $params =~ s/^([|&])// ? $1 : ''; my $and_or = $params =~ s/^([|&])// ? $1 : '';
@ -3875,9 +3864,9 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$target = join( ' ', $target , $mark ); $target = join( ' ', $target , $mark );
} }
} }
} };
sub ipset_command() { my $ipset_command = sub () {
my %xlate = ( ADD => 'add-set' , DEL => 'del-set' ); my %xlate = ( ADD => 'add-set' , DEL => 'del-set' );
require_capability( 'IPSET_MATCH', "$cmd rules", '' ); require_capability( 'IPSET_MATCH', "$cmd rules", '' );
@ -3889,7 +3878,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
fatal_error "Expected ipset name ($setname)" unless $setname =~ /^(6_)?[a-zA-Z][-\w]*$/; fatal_error "Expected ipset name ($setname)" unless $setname =~ /^(6_)?[a-zA-Z][-\w]*$/;
fatal_error "Invalid flags ($flags)" unless defined $flags && $flags =~ /^(dst|src)(,(dst|src)){0,5}$/; fatal_error "Invalid flags ($flags)" unless defined $flags && $flags =~ /^(dst|src)(,(dst|src)){0,5}$/;
$target = join( ' ', 'SET --' . $xlate{$cmd} , $setname , $flags ); $target = join( ' ', 'SET --' . $xlate{$cmd} , $setname , $flags );
} };
my %commands = ( my %commands = (
ADD => { ADD => {
@ -3898,7 +3887,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
minparams => 1, minparams => 1,
maxparams => 1, maxparams => 1,
function => sub() { function => sub() {
ipset_command(); $ipset_command->();
} }
}, },
@ -3950,7 +3939,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
maxparams => 1, maxparams => 1,
function => sub () { function => sub () {
$target = 'CONNMARK'; $target = 'CONNMARK';
handle_mark_param('--set-mark' , HIGHMARK ); $handle_mark_param->('--set-mark' , HIGHMARK );
}, },
}, },
@ -3970,7 +3959,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
minparams => 1, minparams => 1,
maxparams => 1, maxparams => 1,
function => sub() { function => sub() {
ipset_command(); $ipset_command->();
} }
}, },
@ -4188,7 +4177,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
mask => in_hex( $globals{TC_MASK} ), mask => in_hex( $globals{TC_MASK} ),
function => sub () { function => sub () {
$target = 'MARK'; $target = 'MARK';
handle_mark_param('', , HIGHMARK ); $handle_mark_param->('', , HIGHMARK );
}, },
}, },
@ -4200,8 +4189,8 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
function => sub () { function => sub () {
$target = 'CONNMARK '; $target = 'CONNMARK ';
if ( supplied $params ) { if ( supplied $params ) {
handle_mark_param( '--restore-mark --mask ', $handle_mark_param->( '--restore-mark --mask ',
$config{TC_EXPERT} ? HIGHMARK : SMALLMARK ); $config{TC_EXPERT} ? HIGHMARK : SMALLMARK );
} else { } else {
$target .= '--restore-mark --mask ' . in_hex( $globals{TC_MASK} ); $target .= '--restore-mark --mask ' . in_hex( $globals{TC_MASK} );
} }
@ -4236,8 +4225,8 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
function => sub () { function => sub () {
$target = 'CONNMARK '; $target = 'CONNMARK ';
if ( supplied $params ) { if ( supplied $params ) {
handle_mark_param( '--save-mark --mask ' , $handle_mark_param->( '--save-mark --mask ' ,
$config{TC_EXPERT} ? HIGHMARK : SMALLMARK ); $config{TC_EXPERT} ? HIGHMARK : SMALLMARK );
} else { } else {
$target .= '--save-mark --mask ' . in_hex( $globals{TC_MASK} ); $target .= '--save-mark --mask ' . in_hex( $globals{TC_MASK} );
} }
@ -4331,8 +4320,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
minparams => 0 , minparams => 0 ,
maxparams => 16 , maxparams => 16 ,
function => sub() { function => sub() {
fatal_error "A chain desginator may not be specified within an action body" if $designator; fatal_error q('$FW' may not be specified within an action body) if $chainref;
fatal_error q('$FW' may not be specified within an action body) if $chain;
# #
# Create the action:level:tag:param tuple. # Create the action:level:tag:param tuple.
# #
@ -4340,7 +4328,9 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
fatal_error( "Action $cmd invoked Recursively (" . join( '->', map( external_name( $_ ), @actionstack , $normalized_target ) ) . ')' ) if $active{$cmd}; fatal_error( "Action $cmd invoked Recursively (" . join( '->', map( external_name( $_ ), @actionstack , $normalized_target ) ) . ')' ) if $active{$cmd};
if ( my $ref = use_action( $normalized_target ) ) { my $ref = use_action( 'mangle', $normalized_target );
if ( $ref ) {
# #
# First reference to this tuple # First reference to this tuple
# #
@ -4348,7 +4338,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
# #
# process_action may modify both $normalized_target and $ref!!! # process_action may modify both $normalized_target and $ref!!!
# #
process_action( $normalized_target, $ref, $chain ); process_action( $normalized_target, $ref, $chainnames{$chain} );
# #
# Capture the name of the action chain # Capture the name of the action chain
# #
@ -4359,6 +4349,8 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
# #
$target = $usedactions{$normalized_target}->{name}; $target = $usedactions{$normalized_target}->{name};
} }
$commandref->{allowedchains} = $ref->{allowedchains};
} }
}; };
# #
@ -4366,8 +4358,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
# #
if ( $inaction ) { if ( $inaction ) {
( $inaction , undef ) = split( /:/, $chainref->{name}, 2 ) if $chainref->{action}; ( $inaction , undef ) = split( /:/, $chainref->{name}, 2 ) if $chainref->{action};
$chain = $chainref->{name}; $chainnames{$chain = ACTIONCHAIN} = $chainref->{name};
$restriction = $chainref->{restriction} || 0;
} }
( $cmd, $designator ) = split_action( $action ); ( $cmd, $designator ) = split_action( $action );
@ -4383,7 +4374,7 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$actiontype = $builtin_target{$cmd} || $targets{$cmd}; $actiontype = $builtin_target{$cmd} || $targets{$cmd};
my $commandref = $commands{$cmd}; $commandref = $commands{$cmd};
unless ( $commandref ) { unless ( $commandref ) {
fatal_error "Invalid ACTION ($cmd)" unless $actiontype & ACTION; fatal_error "Invalid ACTION ($cmd)" unless $actiontype & ACTION;
@ -4467,10 +4458,12 @@ sub process_mangle_rule1( $$$$$$$$$$$$$$$$$$ ) {
$chain ||= $commandref->{defaultchain}; $chain ||= $commandref->{defaultchain};
$chain ||= $default_chain; $chain ||= $default_chain;
unless ( $inaction ) { if ( $inaction ) {
fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains}; fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chainref->{allowedchains};;
$chain = $chainnames{$chain}; $chainref->{allowedchains} &= $commandref->{allowedchains};
$chainref = ensure_chain( 'mangle', $chain ); } else {
fatal_error "$cmd rules are not allowed in the $chainlabels{$chain} chain" unless $commandref->{allowedchains} & $chain;
$chainref = ensure_chain( 'mangle', $chainnames{$chain} );
} }
if ( ( my $result = expand_rule( $chainref , if ( ( my $result = expand_rule( $chainref ,
@ -4868,32 +4861,4 @@ sub convert_tos($$) {
} }
} }
sub open_mangle_for_output() {
my ( $mangle, $fn1 );
if ( -f ( $fn1 = find_writable_file( 'mangle' ) ) ) {
open( $mangle , '>>', $fn1 ) || fatal_error "Unable to open $fn1:$!";
} else {
open( $mangle , '>', $fn1 ) || fatal_error "Unable to open $fn1:$!";
print $mangle <<'EOF';
#
# Shorewall version 4 - Mangle File
#
# For information about entries in this file, type "man shorewall-mangle"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
# For usage in selecting among multiple ISPs, see
# http://shorewall.net/MultiISP.html
#
# See http://shorewall.net/PacketMarking.html for a detailed description of
# the Netfilter/Shorewall packet marking mechanism.
####################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE USER TEST LENGTH TOS CONNBYTES HELPER PROBABILITY DSCP
# PORT(S) PORT(S)
EOF
}
return ( $mangle, $fn1 );
}
1; 1;

View File

@ -2140,6 +2140,34 @@ sub process_secmark_rule() {
} }
} }
sub open_mangle_for_output() {
my ( $mangle, $fn1 );
if ( -f ( $fn1 = find_writable_file( 'mangle' ) ) ) {
open( $mangle , '>>', $fn1 ) || fatal_error "Unable to open $fn1:$!";
} else {
open( $mangle , '>', $fn1 ) || fatal_error "Unable to open $fn1:$!";
print $mangle <<'EOF';
#
# Shorewall version 4 - Mangle File
#
# For information about entries in this file, type "man shorewall-mangle"
#
# See http://shorewall.net/traffic_shaping.htm for additional information.
# For usage in selecting among multiple ISPs, see
# http://shorewall.net/MultiISP.html
#
# See http://shorewall.net/PacketMarking.html for a detailed description of
# the Netfilter/Shorewall packet marking mechanism.
####################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE USER TEST LENGTH TOS CONNBYTES HELPER PROBABILITY DSCP
# PORT(S) PORT(S)
EOF
}
return ( $mangle, $fn1 );
}
# #
# Process the mangle file and setup traffic shaping # Process the mangle file and setup traffic shaping
# #