mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-22 06:10:42 +01:00
Implement Triggers
Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
parent
411ca87ec3
commit
3c6df56b57
@ -619,6 +619,7 @@ use constant { UNIQUE => 1,
|
||||
COMPLEX => 32,
|
||||
NFACCT => 64,
|
||||
EXPENSIVE => 128,
|
||||
RECENT => 256,
|
||||
};
|
||||
|
||||
our %opttype = ( rule => CONTROL,
|
||||
@ -650,6 +651,7 @@ our %opttype = ( rule => CONTROL,
|
||||
EXCLUSIVE,
|
||||
|
||||
nfacct => NFACCT,
|
||||
recent => RECENT,
|
||||
|
||||
set => EXPENSIVE,
|
||||
geoip => EXPENSIVE,
|
||||
@ -843,7 +845,7 @@ sub set_rule_option( $$$ ) {
|
||||
if ( exists $ruleref->{$option} ) {
|
||||
assert( defined( my $value1 = $ruleref->{$option} ) , $ruleref );
|
||||
|
||||
if ( $opttype & ( MATCH | NFACCT | EXPENSIVE ) ) {
|
||||
if ( $opttype & ( MATCH | NFACCT | RECENT | EXPENSIVE ) ) {
|
||||
if ( $globals{KLUDGEFREE} ) {
|
||||
unless ( reftype $value1 ) {
|
||||
unless ( reftype $value ) {
|
||||
@ -876,7 +878,7 @@ sub set_rule_option( $$$ ) {
|
||||
|
||||
fatal_error "Multiple $option settings in one rule is prohibited";
|
||||
} else {
|
||||
assert(0, $opttype );
|
||||
assert($opttype == TARGET, $opttype );
|
||||
}
|
||||
} else {
|
||||
$ruleref->{$option} = $value;
|
||||
@ -1030,6 +1032,7 @@ sub format_rule( $$;$ ) {
|
||||
#
|
||||
my $ruleref = $rulerefp->{complex} ? clone_irule( $rulerefp ) : $rulerefp;
|
||||
my $nfacct = $rulerefp->{nfacct};
|
||||
my $recent = $rulerefp->{recent};
|
||||
my $expensive;
|
||||
|
||||
for ( @{$ruleref->{matches}} ) {
|
||||
@ -1051,9 +1054,9 @@ sub format_rule( $$;$ ) {
|
||||
next;
|
||||
} elsif ( $type == EXPENSIVE ) {
|
||||
#
|
||||
# Only emit expensive matches now if there are '-m nfacct' matches in the rule
|
||||
# Only emit expensive matches now if there are '-m nfacct' or '-m recent' matches in the rule
|
||||
#
|
||||
if ( $nfacct ) {
|
||||
if ( $nfacct || $recent ) {
|
||||
$rule .= format_option( $_, pop_match( $ruleref, $_ ) );
|
||||
} else {
|
||||
$expensive = 1;
|
||||
@ -1063,7 +1066,7 @@ sub format_rule( $$;$ ) {
|
||||
}
|
||||
}
|
||||
#
|
||||
# Emit expensive matches last unless we had '-m nfacct' matches in the rule.
|
||||
# Emit expensive matches last unless we had '-m nfacct' pr '-m recent' matches in the rule.
|
||||
#
|
||||
if ( $expensive ) {
|
||||
for ( grep( get_opttype( $_, 0 ) == EXPENSIVE, @{$ruleref->{matches}} ) ) {
|
||||
@ -1131,7 +1134,7 @@ sub merge_rules( $$$ ) {
|
||||
}
|
||||
}
|
||||
|
||||
for my $option ( grep ! $opttype{$_} || $_ eq 'nfacct', keys %$fromref ) {
|
||||
for my $option ( grep ! $opttype{$_} || $_ eq 'nfacct' || $_ eq 'recent', keys %$fromref ) {
|
||||
set_rule_option( $toref, $option, $fromref->{$option} );
|
||||
}
|
||||
|
||||
@ -3337,7 +3340,7 @@ sub optimize_level4( $$ ) {
|
||||
while ( @$rulesref ) {
|
||||
my $rule1ref = $rulesref->[-1];
|
||||
|
||||
last unless ( $rule1ref->{target} || '' ) eq $target && ! ( $rule1ref->{targetopts} || $rule1ref->{nfacct} );
|
||||
last unless ( $rule1ref->{target} || '' ) eq $target && ! ( $rule1ref->{targetopts} || $rule1ref->{nfacct} || $rule1ref->{recent} );
|
||||
|
||||
trace ( $chainref, 'D', $rule, $rule1ref ) if $debug;
|
||||
|
||||
@ -6052,9 +6055,11 @@ sub do_ipsec($$) {
|
||||
# Generate a log message
|
||||
#
|
||||
sub log_rule_limit( $$$$$$$$ ) {
|
||||
my ($level, $chainref, $chain, $disposition, $limit, $tag, $command, $matches ) = @_;
|
||||
my ($level, $chainref, $chn, $dispo, $limit, $tag, $command, $matches ) = @_;
|
||||
|
||||
my $prefix = '';
|
||||
my $chain = get_action_chain_name || $chn;
|
||||
my $disposition = get_action_disposition || $dispo;
|
||||
|
||||
$level = validate_level $level; # Do this here again because this function can be called directly from user exits.
|
||||
|
||||
@ -6143,10 +6148,12 @@ sub log_rule_limit( $$$$$$$$ ) {
|
||||
}
|
||||
|
||||
sub log_irule_limit( $$$$$$$@ ) {
|
||||
my ($level, $chainref, $chain, $disposition, $limit, $tag, $command, @matches ) = @_;
|
||||
my ($level, $chainref, $chn, $dispo, $limit, $tag, $command, @matches ) = @_;
|
||||
|
||||
my $prefix = '';
|
||||
my %matches;
|
||||
my $chain = get_action_chain_name || $chn;
|
||||
my $disposition = get_action_disposition || $dispo;
|
||||
|
||||
$level = validate_level $level; # Do this here again because this function can be called directly from user exits.
|
||||
|
||||
|
@ -63,10 +63,13 @@ our @EXPORT = qw(
|
||||
get_action_params
|
||||
get_action_chain
|
||||
get_action_chain_name
|
||||
set_action_name_to_caller
|
||||
get_action_logging
|
||||
get_action_disposition
|
||||
set_action_disposition
|
||||
set_action_param
|
||||
get_inline_matches
|
||||
set_inline_matches
|
||||
|
||||
have_capability
|
||||
require_capability
|
||||
@ -2910,6 +2913,10 @@ sub get_inline_matches() {
|
||||
"$inline_matches ";
|
||||
}
|
||||
|
||||
sub set_inline_matches( $ ) {
|
||||
$inline_matches = $_[0];
|
||||
}
|
||||
|
||||
#
|
||||
# Push/pop acton params
|
||||
#
|
||||
@ -3000,10 +3007,18 @@ sub get_action_chain_name() {
|
||||
$actparms{chain};
|
||||
}
|
||||
|
||||
sub set_action_name_to_caller() {
|
||||
$actparms{chain} = $actparms{caller};
|
||||
}
|
||||
|
||||
sub get_action_disposition() {
|
||||
$actparms{disposition};
|
||||
}
|
||||
|
||||
sub set_action_disposition($) {
|
||||
$actparms{disposition} = $_[0];
|
||||
}
|
||||
|
||||
sub set_action_param( $$ ) {
|
||||
my $i = shift;
|
||||
|
||||
@ -5397,10 +5412,14 @@ sub get_configuration( $$$$ ) {
|
||||
$globals{ZONE_OFFSET} = $config{PROVIDER_BITS};
|
||||
}
|
||||
|
||||
#
|
||||
# It is okay if the trigger mark is outsize of the a 32-bit integer. We check that in IfTrigger"
|
||||
#
|
||||
fatal_error 'Invalid Packet Mark layout' if $config{ZONE_BITS} + $globals{ZONE_OFFSET} > 30;
|
||||
|
||||
$globals{EXCLUSION_MASK} = 1 << ( $globals{ZONE_OFFSET} + $config{ZONE_BITS} );
|
||||
$globals{TPROXY_MARK} = $globals{EXCLUSION_MASK} << 1;
|
||||
$globals{TRIGGER_MARK} = $globals{TPROXY_MARK} << 1;
|
||||
$globals{PROVIDER_MIN} = 1 << $config{PROVIDER_OFFSET};
|
||||
|
||||
$globals{TC_MAX} = make_mask( $config{TC_BITS} );
|
||||
|
@ -2128,11 +2128,11 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) {
|
||||
if ( $basictarget eq 'INLINE' ) {
|
||||
my $inline_matches = get_inline_matches;
|
||||
|
||||
if ( $inline_matches =~ /^(.*\s+)-j\s+(.+) $/ ) {
|
||||
$raw_matches .= $1;
|
||||
if ( $inline_matches =~ /^(.*\s+)?-j\s+(.+) $/ ) {
|
||||
$raw_matches .= $1 if supplied $1;
|
||||
$action = $2;
|
||||
my ( $target ) = split ' ', $action;
|
||||
fatal_error "Unknown jump target ($action)" unless $targets{$target};
|
||||
fatal_error "Unknown jump target ($action)" unless $targets{$target} || $target eq 'MARK';
|
||||
fatal_error "INLINE may not have a parameter when '-j' is specified in the free-form area" if $param ne '';
|
||||
} else {
|
||||
$raw_matches .= $inline_matches;
|
||||
@ -2851,6 +2851,8 @@ sub perl_action_helper($$;$) {
|
||||
|
||||
$matches .= ' ' unless $matches =~ /^(?:.+\s)?$/;
|
||||
|
||||
set_inline_matches $matches if $target =~ /^INLINE(?::.*)?$/;
|
||||
|
||||
if ( $isstatematch ) {
|
||||
if ( $statematch ) {
|
||||
if ( $statematch eq $isstatematch ) {
|
||||
|
86
Shorewall/action.IfTrigger
Normal file
86
Shorewall/action.IfTrigger
Normal file
@ -0,0 +1,86 @@
|
||||
#
|
||||
# Shorewall version 4 - Perform an Action based on a Trigger
|
||||
#
|
||||
# /etc/shorewall/action.IfTrigger
|
||||
#
|
||||
# Parameters:
|
||||
# Trigger: Must start with a letter and be composed of letters, digits, '-', and '_'.
|
||||
# Action: Anything that can appear in the ACTION column of a rule.
|
||||
# Time Limit: Amount of time the trigger is to remain armed in seconds"
|
||||
# Hit Count: Number of packets seen within the Timelimit -- default is 1
|
||||
# Src or Dest: 'src' (default) or 'dst'. Determines if the trigger is associated with the source
|
||||
# address (src) or destination address (dst)
|
||||
# Reset/update: '-' (default) 'reset', or 'update'. If 'reset', the trigger will be reset before
|
||||
# the Action is taken. If 'update', the timestamp associated with the trigger will
|
||||
# be updated and the action taken if the time limit/hitcount are matched.
|
||||
# If '-', the action will be taken if the limit/hitcount are matched but the
|
||||
# trigger's timestamp will not be updated.
|
||||
# Disposition: Disposition for any event generated.
|
||||
#
|
||||
#######################################################################################################
|
||||
# DO NOT REMOVE THE FOLLOWING LINE
|
||||
?format 2
|
||||
#################################################################################################################################################################################################
|
||||
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
|
||||
# PORT PORT(S) DEST LIMIT GROUP
|
||||
|
||||
DEFAULTS -,ACCEPT,60,1,src,check,-
|
||||
|
||||
?begin perl
|
||||
|
||||
use Shorewall::Config qw(:DEFAULT :internal);
|
||||
use Shorewall::Chains;
|
||||
use Shorewall::Rules;
|
||||
use strict;
|
||||
|
||||
my ( $trigger, $action, $timeout, $hitcount, $destination, $reset, $disposition ) = get_action_params( 7 );
|
||||
|
||||
fatal_error "A trigger name is required" unless supplied $trigger;
|
||||
fatal_error "Invalid trigger name ($trigger)" unless $trigger =~ /^[a-zA-z][-\w]*$/;
|
||||
fatal_error "Invalid time limit ($timeout)" unless $timeout =~ /^\d+$/;
|
||||
fatal_error "Invalid hit count ($hitcount)" unless $hitcount =~ /^\d+$/;
|
||||
fatal_error "Invalid Src or Dest ($destination)" unless $destination =~ /^(?:src|dst)$/;
|
||||
fatal_error "Invalid reset flag ($reset)" unless $reset =~ /^(?:reset|update|check)$/;
|
||||
|
||||
set_action_disposition( $disposition) if supplied $disposition;
|
||||
set_action_name_to_caller;
|
||||
|
||||
require_capability 'RECENT_MATCH', 'Use of triggers', 's';
|
||||
|
||||
if ( $reset eq 'reset' ) {
|
||||
require_capability 'MARK_ANYWHERE', 'Resetting a trigger', 's';
|
||||
|
||||
print "Resetting....\n";
|
||||
|
||||
my $mark = $globals{TRIGGER_MARK};
|
||||
#
|
||||
# The trigger mark bit must be within 32 bits
|
||||
#
|
||||
fatal_error "The mark layout does not permit resetting of triggers" unless $mark & 0xffffffff;
|
||||
#
|
||||
# Reset the trigger mark bit
|
||||
#
|
||||
perl_action_helper( 'INLINE', '-j MARK --and-mark '. in_hex( (~ $mark ) & 0xffffffff ) );
|
||||
|
||||
$mark = in_hex $mark;
|
||||
#
|
||||
# Mark the packet if trigger is armed
|
||||
#
|
||||
if ( $destination eq 'dst' ) {
|
||||
perl_action_helper( 'INLINE', "-m recent --rcheck --seconds $timeout --hitcount $hitcount --name $trigger --rdest -j MARK --or-mark $mark" );
|
||||
} else {
|
||||
perl_action_helper( 'INLINE', "-m recent --rcheck --seconds $timeout --hitcount $hitcount --name $trigger --rsource -j MARK --or-mark $mark" );
|
||||
}
|
||||
#
|
||||
# if the trigger is armed, remove it and perform the action
|
||||
#
|
||||
perl_action_helper( $action , "-m mark --mark $mark/$mark -m recent --remove --name $trigger" );
|
||||
} elsif ( $reset eq 'update' ) {
|
||||
perl_action_helper( $action, "-m recent --update --seconds $timeout --hitcount $hitcount --name $trigger" );
|
||||
} else {
|
||||
perl_action_helper( $action, "-m recent --rcheck --seconds $timeout --hitcount $hitcount --name $trigger" );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
?end perl
|
49
Shorewall/action.ResetTrigger
Normal file
49
Shorewall/action.ResetTrigger
Normal file
@ -0,0 +1,49 @@
|
||||
#
|
||||
# Shorewall version 4 - Reset a Trigger
|
||||
#
|
||||
# /etc/shorewall/action.ResetTrigger
|
||||
#
|
||||
# Parameters:
|
||||
# Trigger: Must start with a letter and be composed of letters, digits, '-', and '_'.
|
||||
# Action: Action to perform after setting the trigger. Default is ACCEPT
|
||||
# Src or Dest: 'src' (default) or 'dst'. Determines if the trigger is associated with the source
|
||||
# address (src) or destination address (dst)
|
||||
# Disposition: Disposition for any event generated.
|
||||
#
|
||||
#######################################################################################################
|
||||
# DO NOT REMOVE THE FOLLOWING LINE
|
||||
?format 2
|
||||
#################################################################################################################################################################################################
|
||||
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
|
||||
# PORT PORT(S) DEST LIMIT GROUP
|
||||
|
||||
DEFAULTS -,ACCEPT,src,-
|
||||
|
||||
?begin perl
|
||||
|
||||
use Shorewall::Config;
|
||||
use Shorewall::Chains;
|
||||
use Shorewall::Rules;
|
||||
use strict;
|
||||
|
||||
my ( $trigger, $action, $destination, $disposition ) = get_action_params( 4 );
|
||||
|
||||
require_capability 'RECENT_MATCH', 'Use of triggers', 's';
|
||||
require_capability 'MARK_ANYWHERE', 'Use of triggers', 's';
|
||||
|
||||
fatal_error "A trigger name is required" unless supplied $trigger;
|
||||
fatal_error "Invalid trigger name ($trigger)" unless $trigger =~ /^[a-zA-z][-\w]*$/;
|
||||
fatal_error "Invalid Src or Dest ($destination)" unless $destination =~ /^(?:src|dst)$/;
|
||||
|
||||
set_action_disposition( $disposition) if supplied $disposition;
|
||||
set_action_name_to_caller;
|
||||
|
||||
if ( $destination eq 'dst' ) {
|
||||
perl_action_helper( $action, "-m recent --name $trigger --remove --rdest" );
|
||||
} else {
|
||||
perl_action_helper( $action, "-m recent --name $trigger --remove --rsource" );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
?end perl
|
49
Shorewall/action.SetTrigger
Normal file
49
Shorewall/action.SetTrigger
Normal file
@ -0,0 +1,49 @@
|
||||
#
|
||||
# Shorewall version 4 - Set a Trigger
|
||||
#
|
||||
# /etc/shorewall/action.SetTrigger
|
||||
#
|
||||
# Parameters:
|
||||
# Trigger: Must start with a letter and be composed of letters, digits, '-', and '_'.
|
||||
# Action: Action to perform after setting the trigger. Default is ACCEPT
|
||||
# Src or Dest: 'src' (default) or 'dst'. Determines if the trigger is associated with the source
|
||||
# address (src) or destination address (dst)
|
||||
# Disposition: Disposition for any event generated.
|
||||
#
|
||||
#######################################################################################################
|
||||
# DO NOT REMOVE THE FOLLOWING LINE
|
||||
?format 2
|
||||
#################################################################################################################################################################################################
|
||||
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH HELPER
|
||||
# PORT PORT(S) DEST LIMIT GROUP
|
||||
|
||||
DEFAULTS -,ACCEPT,src
|
||||
|
||||
?begin perl
|
||||
|
||||
use Shorewall::Config;
|
||||
use Shorewall::Chains;
|
||||
use Shorewall::Rules;
|
||||
use strict;
|
||||
|
||||
my ( $trigger, $action, $destination, $disposition ) = get_action_params( 4 );
|
||||
|
||||
require_capability 'RECENT_MATCH', 'Use of triggers', 's';
|
||||
require_capability 'MARK_ANYWHERE', 'Use of triggers', 's';
|
||||
|
||||
fatal_error "A trigger name is required" unless supplied $trigger;
|
||||
fatal_error "Invalid trigger name ($trigger)" unless $trigger =~ /^[a-zA-z][-\w]*$/;
|
||||
fatal_error "Invalid Src or Dest ($destination)" unless $destination =~ /^(?:src|dst)$/;
|
||||
|
||||
set_action_disposition( $disposition) if supplied $disposition;
|
||||
set_action_name_to_caller;
|
||||
|
||||
if ( $destination eq 'dst' ) {
|
||||
perl_action_helper( $action, "-m recent --name $trigger --set --rdest" );
|
||||
} else {
|
||||
perl_action_helper( $action, "-m recent --name $trigger --set --rsource" );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
?end perl
|
@ -33,11 +33,14 @@ Drop # Default Action for DROP policy
|
||||
dropInvalid inline # Drops packets in the INVALID conntrack state
|
||||
DropSmurfs noinline # Drop smurf packets
|
||||
Established inline # Handles packets in the ESTABLISHED state
|
||||
IfTrigger noinline # Perform an action if a trigger is set
|
||||
Invalid inline # Handles packets in the INVALID conntrack state
|
||||
New inline # Handles packets in the NEW conntrack state
|
||||
NotSyn inline # Handles TCP packets which do not have SYN=1 and ACK=0
|
||||
Reject # Default Action for REJECT policy
|
||||
Related inline # Handles packets in the RELATED conntrack state
|
||||
ResetTrigger inline # Reset a Trigger
|
||||
RST inline # Handle packets with RST set
|
||||
SetTrigger inline # Set a trigger for the packet's source IP
|
||||
TCPFlags # Handle bad flag combinations.
|
||||
Untracked inline # Handles packets in the UNTRACKED conntrack state
|
||||
|
Loading…
Reference in New Issue
Block a user