2007-03-15 22:55:22 +01:00
#
2007-06-11 21:39:30 +02:00
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Actions.pm
2007-03-15 22:55:22 +01:00
#
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
#
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
#
# Complete documentation is available at http://shorewall.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of Version 2 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
#
2007-04-19 01:55:25 +02:00
# This module contains the code for dealing with actions (built-in,
# standard and user-defined).
2007-03-15 22:55:22 +01:00
#
2007-03-15 03:18:29 +01:00
package Shorewall::Actions ;
require Exporter ;
use Shorewall::Common ;
use Shorewall::Config ;
use Shorewall::Zones ;
use Shorewall::Chains ;
2007-03-15 03:46:00 +01:00
use Shorewall::Macros ;
2007-03-15 03:18:29 +01:00
use strict ;
our @ ISA = qw( Exporter ) ;
2007-04-08 16:42:26 +02:00
our @ EXPORT = qw( merge_levels
2007-03-15 03:46:00 +01:00
isolate_basic_target
2007-04-08 16:42:26 +02:00
add_requiredby
2007-03-23 00:06:16 +01:00
createlogactionchain
2007-04-08 16:42:26 +02:00
createactionchain
2007-03-15 03:46:00 +01:00
find_logactionchain
process_actions1
process_actions2
process_actions3
2007-03-27 01:17:46 +02:00
2007-04-08 16:42:26 +02:00
% usedactions
% default_actions
2007-03-15 03:46:00 +01:00
% actions
) ;
2007-06-14 01:02:39 +02:00
our @ EXPORT_OK = qw( initialize ) ;
2007-03-15 03:18:29 +01:00
our @ VERSION = 1.00 ;
#
# Used Actions. Each action that is actually used has an entry with value 1.
#
our % usedactions ;
2007-06-14 01:02:39 +02:00
## Firewall to DMZ
2007-03-15 03:18:29 +01:00
#
2007-06-14 01:02:39 +02:00
2007-03-15 03:18:29 +01:00
# Default actions for each policy.
#
2007-06-14 01:02:39 +02:00
our % default_actions ;
2007-03-15 03:18:29 +01:00
2007-03-15 03:46:00 +01:00
# Action Table
#
# %actions{ <action1> => { requires => { <requisite1> = 1,
# <requisite2> = 1,
# ...
# } ,
# actchain => <action chain number> # Used for generating unique chain names for each <level>:<tag> pair.
#
our % actions ;
#
# Contains an entry for each used <action>:<level>[:<tag>] that maps to the associated chain.
#
my % logactionchains ;
#
2007-06-15 00:07:45 +02:00
# Initialize globals -- we take this novel approach to globals initialization to allow
# the compiler to run multiple times in the same process. The
# initialize() function does globals initialization for this
# module and is called from an INIT block below. The function is
# also called by Shorewall::Compiler::compiler at the beginning of
# the second and subsequent calls to that function.
2007-03-15 03:46:00 +01:00
#
2007-06-14 01:02:39 +02:00
sub initialize () {
% default_actions = ( DROP = > 'none' ,
REJECT = > 'none' ,
ACCEPT = > 'none' ,
QUEUE = > 'none' ) ;
% actions = ( ) ;
% logactionchains = ( ) ;
}
INIT {
initialize ;
}
2007-06-15 00:07:45 +02:00
#
# This function determines the logging for a subordinate action or a rule within a superior action
#
2007-03-15 03:46:00 +01:00
sub merge_levels ($$) {
my ( $ superior , $ subordinate ) = @ _ ;
my @ supparts = split /:/ , $ superior ;
my @ subparts = split /:/ , $ subordinate ;
my $ subparts = @ subparts ;
my $ target = $ subparts [ 0 ] ;
push @ subparts , '' while @ subparts < 3 ; #Avoid undefined values
my $ level = $ supparts [ 1 ] ;
my $ tag = $ supparts [ 2 ] ;
if ( @ supparts == 3 ) {
return "$target:none!:$tag" if $ level eq 'none!' ;
return "$target:$level:$tag" if $ level =~ /!$/ ;
return $ subordinate if $ subparts >= 2 ;
2007-05-02 17:39:36 +02:00
return "$target:$level:$tag" ;
2007-04-08 16:42:26 +02:00
}
2007-03-15 03:46:00 +01:00
if ( @ supparts == 2 ) {
return "$target:none!" if $ level eq 'none!' ;
return "$target:$level" if ( $ level =~ /!$/ ) || ( $ subparts < 2 ) ;
}
$ subordinate ;
}
2007-03-26 23:49:03 +02:00
#
# Get Macro Name -- strips away trailing /* and :* from the first column in a rule, macro or action.
2007-03-15 03:46:00 +01:00
#
sub isolate_basic_target ( $ ) {
2007-05-02 18:22:08 +02:00
( split '[/:]' , $ _ [ 0 ] ) [ 0 ] ;
2007-03-15 03:46:00 +01:00
}
#
# Define an Action
#
sub new_action ( $ ) {
my $ action = $ _ [ 0 ] ;
my % h ;
$ h { actchain } = '' ;
$ h { requires } = { } ;
$ actions { $ action } = \ % h ;
}
#
2007-03-24 22:12:10 +01:00
# Record a 'requires' relationship between a pair of actions.
2007-03-15 03:46:00 +01:00
#
sub add_requiredby ( $$ ) {
2007-03-24 22:12:10 +01:00
my ( $ requiredby , $ requires ) = @ _ ;
$ actions { $ requires } { requires } { $ requiredby } = 1 ;
2007-03-15 03:46:00 +01:00
}
#
# Create and record a log action chain -- Log action chains have names
# that are formed from the action name by prepending a "%" and appending
# a 1- or 2-digit sequence number. In the functions that follow,
# the CHAIN, LEVEL and TAG variable serves as arguments to the user's
# exit. We call the exit corresponding to the name of the action but we
# set CHAIN to the name of the iptables chain where rules are to be added.
# Similarly, LEVEL and TAG contain the log level and log tag respectively.
#
# The maximum length of a chain name is 30 characters -- since the log
# action chain name is 2-3 characters longer than the base chain name,
# this function truncates the original chain name where necessary before
2007-03-24 22:12:10 +01:00
# it adds the leading "%" and trailing sequence number.
2007-04-08 16:42:26 +02:00
#
2007-03-15 03:46:00 +01:00
sub createlogactionchain ( $$ ) {
my ( $ action , $ level ) = @ _ ;
my $ chain = $ action ;
my $ actionref = $ actions { $ action } ;
my $ chainref ;
$ chain = substr $ chain , 0 , 28 if ( length $ chain ) > 28 ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
while ( $ chain_table { '%' . $ chain . $ actionref - > { actchain } } ) {
$ chain = substr $ chain , 0 , 27 if $ actionref - > { actchain } == 10 and length $ chain == 28 ;
}
$ actionref = new_action $ action unless $ actionref ;
$ level = 'none' unless $ level ;
2007-03-23 00:06:16 +01:00
$ logactionchains { "$action:$level" } = $ chainref = new_chain 'filter' , '%' . $ chain . $ actionref - > { actchain } + + ;
2007-03-15 03:46:00 +01:00
2007-05-03 18:02:24 +02:00
mark_referenced $ chainref ; # Just in case the action body is empty.
2007-03-23 00:06:16 +01:00
unless ( $ targets { $ action } & STANDARD ) {
2007-05-03 18:02:24 +02:00
2007-03-23 00:06:16 +01:00
my $ file = find_file $ chain ;
if ( - f $ file ) {
progress_message "Processing $file..." ;
2007-05-02 18:43:58 +02:00
unless ( my $ return = eval `cat $file` ) {
2007-03-23 00:06:16 +01:00
fatal_error "Couldn't parse $file: $@" if $@ ;
fatal_error "Couldn't do $file: $!" unless defined $ return ;
fatal_error "Couldn't run $file" unless $ return ;
}
}
}
2007-03-15 03:46:00 +01:00
}
2007-05-03 18:02:24 +02:00
sub createsimpleactionchain ( $ ) {
my $ action = shift ;
my $ chainref = new_chain 'filter' , $ action ;
$ logactionchains { "$action:none" } = $ chainref ;
mark_referenced $ chainref ; # Just in case the action body is empty.
unless ( $ targets { $ action } & STANDARD ) {
my $ file = find_file $ action ;
if ( - f $ file ) {
progress_message "Processing $file..." ;
unless ( my $ return = eval `cat $file` ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
fatal_error "Couldn't do $file: $!" unless defined $ return ;
fatal_error "Couldn't run $file" unless $ return ;
}
}
}
}
2007-03-15 03:46:00 +01:00
#
# Create an action chain and run it's associated user exit
#
sub createactionchain ( $ ) {
my ( $ action , $ level ) = split_action $ _ [ 0 ] ;
2007-05-03 18:02:24 +02:00
my $ chainref ;
2007-05-03 18:30:59 +02:00
if ( defined $ level && $ level ne '' ) {
2007-03-15 03:46:00 +01:00
if ( $ level eq 'none' ) {
2007-05-03 18:02:24 +02:00
createsimpleactionchain $ action ;
2007-03-15 03:46:00 +01:00
} else {
createlogactionchain $ action , $ level ;
}
} else {
2007-05-03 18:02:24 +02:00
createsimpleactionchain $ action ;
2007-03-15 03:46:00 +01:00
}
}
#
# Find the chain that handles the passed action. If the chain cannot be found,
# a fatal error is generated and the function does not return.
#
sub find_logactionchain ( $ ) {
my $ fullaction = $ _ [ 0 ] ;
my ( $ action , $ level ) = split_action $ fullaction ;
$ level = 'none' unless $ level ;
fatal_error "Fatal error in find_logactionchain" unless $ logactionchains { "$action:$level" } ;
}
#
2007-05-13 17:49:43 +02:00
# The functions process_actions1-3() implement the three phases of action processing.
2007-03-15 03:46:00 +01:00
#
# The first phase (process_actions1) occurs before the rules file is processed. ${SHAREDIR}/actions.std
# and ${CONFDIR}/actions are scanned (in that order) and for each action:
#
# a) The related action definition file is located and scanned.
# b) Forward and unresolved action references are trapped as errors.
# c) A dependency graph is created using the 'requires' field in the 'actions' table.
#
# As the rules file is scanned, each action[:level[:tag]] is merged onto the 'usedactions' hash. When an <action>
# is merged into the hash, its action chain is created. Where logging is specified, a chain with the name
# %<action>n is used where the <action> name is truncated on the right where necessary to ensure that the total
# length of the chain name does not exceed 30 characters.
#
# The second phase (process_actions2) occurs after the rules file is scanned. The transitive closure of
# %usedactions is generated; again, as new actions are merged into the hash, their action chains are created.
#
# The final phase (process_actions3) is to traverse the keys of %usedactions populating each chain appropriately
# by reading the action definition files and creating rules. Note that a given action definition file is
# processed once for each unique [:level[:tag]] applied to an invocation of the action.
2007-03-27 01:17:46 +02:00
#
2007-05-13 17:49:43 +02:00
sub process_macro1 ( $$ ) {
my ( $ action , $ macrofile ) = @ _ ;
progress_message " ..Expanding Macro $macrofile..." ;
push_open ( $ macrofile ) ;
while ( read_a_line ) {
my ( $ mtarget , $ msource , $ mdest , $ mproto , $ mports , $ msports , $ mrate , $ muser ) = split_line 1 , 8 , 'macro file' ;
$ mtarget =~ s/:.*$// ;
my $ targettype = $ targets { $ mtarget } ;
$ targettype = 0 unless defined $ targettype ;
fatal_error "Invalid target ($mtarget)"
unless ( $ targettype == STANDARD ) || ( $ mtarget eq 'PARAM' ) || ( $ mtarget eq 'LOG' ) ;
}
progress_message " ..End Macro $macrofile" ;
pop_open ;
}
sub process_action1 ( $$ ) {
my ( $ action , $ wholetarget ) = @ _ ;
my ( $ target , $ level ) = split_action $ wholetarget ;
$ level = 'none' unless $ level ;
my $ targettype = $ targets { $ target } ;
if ( defined $ targettype ) {
return if ( $ targettype == STANDARD ) || ( $ targettype == MACRO ) || ( $ target eq 'LOG' ) ;
fatal_error "Invalid TARGET ($target)" if $ targettype & STANDARD ;
fatal_error "An action may not invoke itself" if $ target eq $ action ;
add_requiredby $ wholetarget , $ action if $ targettype & ACTION ;
} elsif ( $ target eq 'COMMENT' ) {
fatal_error "Invalid TARGET ($wholetarget)" unless $ wholetarget eq $ target ;
} else {
2007-05-13 19:00:19 +02:00
( $ target , my $ param ) = split '/' , $ target ;
if ( defined $ param ) {
my $ paramtype = $ targets { $ param } || 0 ;
fatal_error "Parameter value not allowed in action files ($param)" if $ paramtype & NATRULE ;
}
2007-05-13 17:49:43 +02:00
2007-06-16 23:08:12 +02:00
fatal_error "Invalid or missing ACTION ($wholetarget)" unless defined $ target ;
2007-05-22 01:09:40 +02:00
2007-05-13 17:49:43 +02:00
if ( find_macro $ target ) {
process_macro1 ( $ action , $ macros { $ target } ) ;
} else {
fatal_error "Invalid TARGET ($target)" ;
}
}
}
2007-03-15 03:46:00 +01:00
sub process_actions1 () {
for my $ act ( grep $ targets { $ _ } & ACTION , keys % targets ) {
new_action $ act ;
}
2007-04-08 16:42:26 +02:00
2007-03-29 17:47:47 +02:00
for my $ file ( qw/actions.std actions/ ) {
open_file $ file ;
2007-03-15 03:46:00 +01:00
2007-03-29 17:47:47 +02:00
while ( read_a_line ) {
2007-04-01 17:38:05 +02:00
my ( $ action ) = split_line 1 , 1 , 'action file' ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ action =~ /:/ ) {
warning_message 'Default Actions are now specified in /etc/shorewall/shorewall.conf' ;
$ action =~ s/:.*$// ;
}
next unless $ action ;
if ( $ targets { $ action } ) {
next if $ targets { $ action } & ACTION ;
2007-06-16 23:08:12 +02:00
fatal_error "Invalid Action Name ($action)" ;
2007-03-15 03:46:00 +01:00
}
2007-05-02 23:59:11 +02:00
$ targets { $ action } = ACTION ;
2007-06-16 23:08:12 +02:00
fatal_error "Invalid Action Name ($action)" unless "\L$action" =~ /^[a-z]\w*$/ ;
2007-03-15 03:46:00 +01:00
2007-05-02 23:59:11 +02:00
new_action $ action ;
2007-03-15 03:46:00 +01:00
my $ actionfile = find_file "action.$action" ;
2007-06-16 23:08:12 +02:00
fatal_error "Missing Action File ($actionfile)" unless - f $ actionfile ;
2007-03-15 03:46:00 +01:00
progress_message2 " Pre-processing $actionfile..." ;
2007-03-29 17:47:47 +02:00
push_open ( $ actionfile ) ;
2007-03-15 03:46:00 +01:00
2007-03-29 17:47:47 +02:00
while ( read_a_line ) {
2007-03-27 01:17:46 +02:00
2007-04-01 17:38:05 +02:00
my ( $ wholetarget , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ users ) = split_line 1 , 8 , 'action file' ;
2007-03-15 03:46:00 +01:00
2007-05-13 17:49:43 +02:00
process_action1 ( $ action , $ wholetarget ) ;
2007-03-29 17:47:47 +02:00
2007-03-15 03:46:00 +01:00
}
2007-03-29 17:47:47 +02:00
pop_open ;
2007-03-15 03:46:00 +01:00
}
}
}
2007-04-08 16:42:26 +02:00
sub process_actions2 () {
progress_message2 'Generating Transitive Closure of Used-action List...' ;
2007-03-15 03:46:00 +01:00
my $ changed = 1 ;
while ( $ changed ) {
$ changed = 0 ;
for my $ target ( keys % usedactions ) {
my ( $ action , $ level ) = split_action $ target ;
my $ actionref = $ actions { $ action } ;
2007-05-03 18:02:24 +02:00
fatal_error "Null Action Reference in process_actions2" unless $ actionref ;
2007-03-15 03:46:00 +01:00
for my $ action1 ( keys % { $ actionref - > { requires } } ) {
my $ action2 = merge_levels $ target , $ action1 ;
unless ( $ usedactions { $ action2 } ) {
$ usedactions { $ action2 } = 1 ;
createactionchain $ action2 ;
$ changed = 1 ;
}
}
}
}
}
2007-03-27 01:17:46 +02:00
2007-05-13 18:30:19 +02:00
#
# This function is called to process each rule generated from an action file.
#
sub process_action ( $$$$$$$$$$ ) {
my ( $ chainref , $ actionname , $ target , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ user ) = @ _ ;
my ( $ action , $ level ) = split_action $ target ;
expand_rule ( $ chainref ,
NO_RESTRICT ,
do_proto ( $ proto , $ ports , $ sports ) . do_ratelimit ( $ rate , $ action ) . do_user $ user ,
$ source ,
$ dest ,
'' , #Original Dest
'-j ' . ( $ action eq 'REJECT' ? 'reject' : $ action eq 'CONTINUE' ? 'RETURN' : $ action ) ,
$ level ,
$ action ,
'' ) ;
}
#
# Expand Macro in action file4s.
#
sub process_macro3 ( $$$$$$$$$$$ ) {
my ( $ fn , $ param , $ chainref , $ action , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ user ) = @ _ ;
progress_message "..Expanding Macro $fn..." ;
push_open $ fn ;
my $ standard = ( $ fn =~ /^($globals{SHAREDIR})/ ) ;
while ( read_a_line ) {
my ( $ mtarget , $ msource , $ mdest , $ mproto , $ mports , $ msports , $ mrate , $ muser ) = split_line 1 , 8 , 'macro file' ;
if ( $ mtarget =~ /^PARAM:?/ ) {
fatal_error 'PARAM requires that a parameter be supplied in macro invocation' unless $ param ;
$ mtarget = substitute_param $ param , $ mtarget ;
}
if ( $ msource ) {
if ( ( $ msource eq '-' ) || ( $ msource eq 'SOURCE' ) ) {
$ msource = $ source || '' ;
} elsif ( $ msource eq 'DEST' ) {
$ msource = $ dest || '' ;
} else {
$ msource = merge_macro_source_dest $ msource , $ source ;
}
} else {
$ msource = '' ;
}
$ msource = '' if $ msource eq '-' ;
if ( $ mdest ) {
if ( ( $ mdest eq '-' ) || ( $ mdest eq 'DEST' ) ) {
$ mdest = $ dest || '' ;
} elsif ( $ mdest eq 'SOURCE' ) {
$ mdest = $ source || '' ;
} else {
$ mdest = merge_macro_source_dest $ mdest , $ dest ;
}
} else {
$ mdest = '' ;
}
$ mdest = '' if $ mdest eq '-' ;
$ mproto = merge_macro_column $ mproto , $ proto ;
$ mports = merge_macro_column $ mports , $ ports ;
$ msports = merge_macro_column $ msports , $ sports ;
$ mrate = merge_macro_column $ mrate , $ rate ;
$ muser = merge_macro_column $ muser , $ user ;
process_action $ chainref , $ action , $ mtarget , $ msource , $ mdest , $ mproto , $ mports , $ msports , $ mrate , $ muser ;
}
pop_open ;
progress_message '..End Macro'
}
2007-03-15 03:46:00 +01:00
#
# Generate chain for non-builtin action invocation
2007-03-27 01:17:46 +02:00
#
2007-03-15 03:46:00 +01:00
sub process_action3 ( $$$$$ ) {
2007-03-24 22:12:10 +01:00
my ( $ chainref , $ wholeaction , $ action , $ level , $ tag ) = @ _ ;
2007-03-15 03:46:00 +01:00
my $ actionfile = find_file "action.$action" ;
2007-03-31 19:44:16 +02:00
my $ standard = ( $ actionfile =~ /^$globals{SHAREDIR}/ ) ;
2007-04-08 16:42:26 +02:00
2007-06-16 23:08:12 +02:00
fatal_error "Missing Action File ($actionfile)" unless - f $ actionfile ;
2007-04-08 16:42:26 +02:00
2007-03-15 03:46:00 +01:00
progress_message2 "Processing $actionfile for chain $chainref->{name}..." ;
2007-03-29 19:02:13 +02:00
open_file $ actionfile ;
2007-03-15 03:46:00 +01:00
2007-03-29 19:02:13 +02:00
while ( read_a_line ) {
2007-03-27 01:17:46 +02:00
2007-05-10 17:29:41 +02:00
my ( $ target , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ user ) = split_line1 1 , 8 , 'action file' ;
2007-03-15 03:46:00 +01:00
2007-05-03 16:24:56 +02:00
if ( $ target eq 'COMMENT' ) {
2007-05-09 20:22:40 +02:00
process_comment ;
2007-05-03 16:24:56 +02:00
next ;
}
2007-03-15 03:46:00 +01:00
my $ target2 = merge_levels $ wholeaction , $ target ;
my ( $ action2 , $ level2 ) = split_action $ target2 ;
my $ action2type = $ targets { isolate_basic_target $ action2 } ;
unless ( $ action2type == STANDARD ) {
2007-05-03 16:24:56 +02:00
if ( $ action2type & ACTION ) {
2007-03-15 03:46:00 +01:00
$ target2 = ( find_logactionchain ( $ target = $ target2 ) ) - > { name } ;
} else {
2007-05-03 02:56:36 +02:00
die "Internal Error" unless $ action2type == MACRO || $ action2type & LOGRULE ;
2007-03-15 03:46:00 +01:00
}
}
if ( $ action2type == MACRO ) {
( $ action2 , my $ param ) = split '/' , $ action2 ;
fatal_error "Null Macro" unless my $ fn = $ macros { $ action2 } ;
2007-05-13 18:30:19 +02:00
process_macro3 ( $ fn , $ param , $ chainref , $ action , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ user ) ;
2007-03-15 03:46:00 +01:00
} else {
process_action $ chainref , $ action , $ target2 , $ source , $ dest , $ proto , $ ports , $ sports , $ rate , $ user ;
2007-04-08 16:42:26 +02:00
}
2007-03-15 03:46:00 +01:00
}
$ comment = '' ;
2007-03-27 01:17:46 +02:00
}
2007-03-15 03:46:00 +01:00
sub process_actions3 () {
#
# The following small functions generate rules for the builtin actions of the same name
#
sub dropBcast ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ level ) {
2007-03-29 03:29:27 +02:00
log_rule_limit $ level , $ chainref , 'dropBcast' , 'DROP' , '' , $ tag , 'add' , ' -m addrtype --dst-type BROADCAST' ;
2007-05-15 22:40:15 +02:00
log_rule_limit $ level , $ chainref , 'dropBcast' , 'DROP' , '' , $ tag , 'add' , ' -d 224.0.0.0/4' ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-29 03:29:27 +02:00
add_rule $ chainref , '-m addrtype --dst-type BROADCAST -j DROP' ;
2007-05-15 22:40:15 +02:00
add_rule $ chainref , '-d 224.0.0.0/4 -j DROP' ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub allowBcast ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ level ) {
2007-03-29 03:29:27 +02:00
log_rule_limit $ level , $ chainref , 'allowBcast' , 'ACCEPT' , '' , $ tag , 'add' , ' -m addrtype --dst-type BROADCAST' ;
2007-05-15 22:40:15 +02:00
log_rule_limit $ level , $ chainref , 'allowBcast' , 'ACCEPT' , '' , $ tag , 'add' , ' -d 224.0.0.0/4' ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-29 03:29:27 +02:00
add_rule $ chainref , '-m addrtype --dst-type BROADCAST -j ACCEPT' ;
2007-05-15 22:40:15 +02:00
add_rule $ chainref , '-d 224.0.0.0/4 -j ACCEPT' ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub dropNotSyn ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-04-08 16:42:26 +02:00
log_rule_limit $ level , $ chainref , 'dropNotSyn' , 'DROP' , '' , $ tag , 'add' , '-p tcp ! --syn ' if $ level ;
2007-03-15 03:46:00 +01:00
add_rule $ chainref , '-p tcp ! --syn -j DROP' ;
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub rejNotSyn ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-04-08 16:42:26 +02:00
log_rule_limit $ level , $ chainref , 'rejNotSyn' , 'REJECT' , '' , $ tag , 'add' , '-p tcp ! --syn ' if $ level ;
2007-05-19 15:49:56 +02:00
add_rule $ chainref , '-p tcp ! --syn -j REJECT --reject-with tcp-reset' ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub dropInvalid ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-04-08 16:42:26 +02:00
log_rule_limit $ level , $ chainref , 'dropInvalid' , 'DROP' , '' , $ tag , 'add' , '-m state --state INVALID ' if $ level ;
2007-04-18 22:36:19 +02:00
add_rule $ chainref , '-m state --state INVALID -j DROP' ;
2007-03-15 03:46:00 +01:00
}
sub allowInvalid ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-04-08 16:42:26 +02:00
log_rule_limit $ level , $ chainref , 'allowInvalid' , 'ACCEPT' , '' , $ tag , 'add' , '-m state --state INVALID ' if $ level ;
2007-03-15 03:46:00 +01:00
add_rule $ chainref , '-m state --state INVALID -j ACCEPT' ;
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub forwardUPnP ( $$$ ) {
}
sub allowinUPnP ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ level ) {
log_rule_limit $ level , $ chainref , 'allowinUPnP' , 'ACCEPT' , '' , $ tag , 'add' , '-p udp --dport 1900 ' ;
log_rule_limit $ level , $ chainref , 'allowinUPnP' , 'ACCEPT' , '' , $ tag , 'add' , '-p tcp --dport 49152 ' ;
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
add_rule $ chainref , '-p udp --dport 1900 -j ACCEPT' ;
add_rule $ chainref , '-p tcp --dport 49152 -j ACCEPT' ;
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
sub Limit ( $$$ ) {
my ( $ chainref , $ level , $ tag ) = @ _ ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
my @ tag = split /,/ , $ tag ;
2007-03-27 01:17:46 +02:00
2007-05-10 19:07:46 +02:00
fatal_error 'Limit rules must include <set name>,<max connections>,<interval> as the log tag (' . join ( ':' , 'Limit' , $ level eq '' ? 'none' : $ level , $ tag ) . ')' unless @ tag == 3 ;
2007-03-21 18:54:17 +01:00
my $ set = $ tag [ 0 ] ;
2007-05-10 18:13:16 +02:00
2007-05-10 18:25:20 +02:00
for ( @ tag [ 1 , 2 ] ) {
2007-05-10 19:07:46 +02:00
fatal_error 'Max connections and interval in Limit rules must be numeric (' . join ( ':' , 'Limit' , $ level eq '' ? 'none' : $ level , $ tag ) . ')' unless /^\d+$/
2007-05-10 18:13:16 +02:00
}
2007-03-21 18:54:17 +01:00
my $ count = $ tag [ 1 ] + 1 ;
2007-05-04 17:12:29 +02:00
require_capability ( 'RECENT_MATCH' , 'Limit rules' , '' ) ;
2007-03-29 03:29:27 +02:00
2007-03-21 18:54:17 +01:00
add_rule $ chainref , "-m recent --name $set --set" ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ level ) {
my $ xchainref = new_chain 'filter' , "$chainref->{name}%" ;
log_rule_limit $ level , $ xchainref , $ tag [ 0 ] , 'DROP' , '' , '' , 'add' , '' ;
add_rule $ xchainref , '-j DROP' ;
2007-05-27 00:20:21 +02:00
add_rule $ chainref , "-m recent --name $set --update --seconds $tag[2] --hitcount $count -j $xchainref->{name}" ;
2007-03-15 03:46:00 +01:00
} else {
2007-03-21 18:54:17 +01:00
add_rule $ chainref , "-m recent --update --name $set --seconds $tag[2] --hitcount $count -j DROP" ;
2007-03-15 03:46:00 +01:00
}
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
add_rule $ chainref , '-j ACCEPT' ;
}
my % builtinops = ( 'dropBcast' = > \ & dropBcast ,
'allowBcast' = > \ & allowBcast ,
'dropNotSyn' = > \ & dropNotSyn ,
'rejNotSyn' = > \ & rejNotSyn ,
'dropInvalid' = > \ & dropInvalid ,
'allowInvalid' = > \ & allowInvalid ,
'allowinUPnP' = > \ & allowinUPnP ,
'forwardUPnP' = > \ & forwardUPnP ,
'Limit' = > \ & Limit ,
) ;
for my $ wholeaction ( keys % usedactions ) {
my $ chainref = find_logactionchain $ wholeaction ;
my ( $ action , $ level , $ tag ) = split /:/ , $ wholeaction ;
$ level = '' unless defined $ level ;
$ tag = '' unless defined $ tag ;
2007-03-27 01:17:46 +02:00
2007-03-15 03:46:00 +01:00
if ( $ targets { $ action } & BUILTIN ) {
$ level = '' if $ level =~ /none!?/ ;
$ builtinops { $ action } - > ( $ chainref , $ level , $ tag ) ;
} else {
process_action3 $ chainref , $ wholeaction , $ action , $ level , $ tag ;
}
2007-03-27 01:17:46 +02:00
}
2007-03-15 03:46:00 +01:00
}
2007-03-15 03:18:29 +01:00
1 ;