2009-02-22 18:30:14 +01:00
#
2010-12-15 20:57:51 +01:00
# Shorewall 4.4 -- /usr/share/shorewall/Shorewall/Misc.pm
2009-02-22 18:30:14 +01:00
#
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
#
2011-05-23 19:06:56 +02:00
# (c) 2007,2008,2009,2010,2011 - Tom Eastep (teastep@shorewall.net)
2009-02-22 18:30:14 +01:00
#
# 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,
2011-02-21 00:35:58 +01:00
# but WITHOUT ANY WARRANTY; without even the implied warranty ofs
2009-02-22 18:30:14 +01:00
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
2010-12-29 02:18:43 +01:00
# This module contains those routines that don't seem to fit well elsewhere. It
# was carved from the Rules module in 4.4.16.
2009-02-22 18:30:14 +01:00
#
2010-12-15 20:57:51 +01:00
package Shorewall::Misc ;
2009-02-22 18:30:14 +01:00
require Exporter ;
2009-11-02 16:15:20 +01:00
2009-02-22 18:30:14 +01:00
use Shorewall::Config qw( :DEFAULT :internal ) ;
use Shorewall::IPAddrs ;
use Shorewall::Zones ;
use Shorewall::Chains qw( :DEFAULT :internal ) ;
2011-02-20 20:28:47 +01:00
use Shorewall::Rules ;
2009-02-22 18:30:14 +01:00
use Shorewall::Proc ;
use strict ;
our @ ISA = qw( Exporter ) ;
our @ EXPORT = qw( process_tos
setup_ecn
add_common_rules
setup_mac_lists
2009-09-08 21:54:23 +02:00
process_routestopped
2009-03-28 20:22:15 +01:00
compile_stop_firewall
2010-12-15 20:57:51 +01:00
generate_matrix
2009-02-22 18:30:14 +01:00
) ;
2010-12-12 02:16:50 +01:00
our @ EXPORT_OK = qw( initialize ) ;
2011-04-19 19:02:29 +02:00
our $ VERSION = '4.4_20' ;
2009-02-22 18:30:14 +01:00
2011-05-14 22:21:31 +02:00
my $ family ;
2010-12-12 02:16:50 +01:00
2009-02-22 18:30:14 +01:00
#
2009-08-20 23:32:15 +02:00
# Rather than initializing globals in an INIT block or during declaration,
2009-08-16 18:24:51 +02:00
# we initialize them in a function. This is done for two reasons:
#
2009-08-17 19:45:46 +02:00
# 1. Proper initialization depends on the address family which isn't
2009-08-16 18:24:51 +02:00
# known until the compiler has started.
#
# 2. The compiler can run multiple times in the same process so it has to be
2009-08-17 19:45:46 +02:00
# able to re-initialize its dependent modules' state.
2009-02-22 18:30:14 +01:00
#
sub initialize ( $ ) {
$ family = shift ;
}
sub process_tos () {
2010-01-25 16:56:16 +01:00
my $ chain = have_capability ( 'MANGLE_FORWARD' ) ? 'fortos' : 'pretos' ;
my $ stdchain = have_capability ( 'MANGLE_FORWARD' ) ? 'FORWARD' : 'PREROUTING' ;
2009-02-22 18:30:14 +01:00
my % tosoptions = ( 'minimize-delay' = > 0x10 ,
'maximize-throughput' = > 0x08 ,
'maximize-reliability' = > 0x04 ,
'minimize-cost' = > 0x02 ,
'normal-service' = > 0x00 ) ;
if ( my $ fn = open_file 'tos' ) {
my $ first_entry = 1 ;
my ( $ pretosref , $ outtosref ) ;
first_entry ( sub { progress_message2 "$doing $fn..." ; $ pretosref = ensure_chain 'mangle' , $ chain ; $ outtosref = ensure_chain 'mangle' , 'outtos' ; } ) ;
while ( read_a_line ) {
my ( $ src , $ dst , $ proto , $ sports , $ ports , $ tos , $ mark ) = split_line 6 , 7 , 'tos file entry' ;
$ first_entry = 0 ;
fatal_error 'A value must be supplied in the TOS column' if $ tos eq '-' ;
if ( defined ( my $ tosval = $ tosoptions { "\L$tos" } ) ) {
$ tos = $ tosval ;
} else {
my $ val = numeric_value ( $ tos ) ;
fatal_error "Invalid TOS value ($tos)" unless defined ( $ val ) && $ val < 0x1f ;
}
my $ chainref ;
my $ restriction = NO_RESTRICT ;
my ( $ srczone , $ source , $ remainder ) ;
if ( $ family == F_IPV4 ) {
( $ srczone , $ source , $ remainder ) = split ( /:/ , $ src , 3 ) ;
fatal_error 'Invalid SOURCE' if defined $ remainder ;
2010-01-08 22:54:31 +01:00
} elsif ( $ src =~ /^(.+?):<(.*)>\s*$/ || $ src =~ /^(.+?):\[(.*)\]\s*$/ ) {
2009-02-22 18:30:14 +01:00
$ srczone = $ 1 ;
$ source = $ 2 ;
} else {
$ srczone = $ src ;
}
if ( $ srczone eq firewall_zone ) {
$ chainref = $ outtosref ;
$ src = $ source || '-' ;
$ restriction = OUTPUT_RESTRICT ;
} else {
$ chainref = $ pretosref ;
$ src =~ s/^all:?// ;
}
$ dst =~ s/^all:?// ;
expand_rule
$ chainref ,
$ restriction ,
2010-01-13 19:50:14 +01:00
do_proto ( $ proto , $ ports , $ sports ) . do_test ( $ mark , $ globals { TC_MASK } ) ,
2009-02-22 18:30:14 +01:00
$ src ,
$ dst ,
'' ,
2010-08-26 19:37:07 +02:00
"TOS --set-tos $tos" ,
2009-02-22 18:30:14 +01:00
'' ,
2010-08-26 17:40:24 +02:00
'TOS' ,
2009-02-22 18:30:14 +01:00
'' ;
}
unless ( $ first_entry ) {
2010-01-16 18:53:53 +01:00
add_jump ( $ mangle_table - > { $ stdchain } , $ chain , 0 ) if $ pretosref - > { referenced } ;
add_jump ( $ mangle_table - > { OUTPUT } , 'outtos' , 0 ) if $ outtosref - > { referenced } ;
2009-02-22 18:30:14 +01:00
}
}
}
#
# Setup ECN disabling rules
#
sub setup_ecn ()
{
my % interfaces ;
my @ hosts ;
if ( my $ fn = open_file 'ecn' ) {
first_entry "$doing $fn..." ;
while ( read_a_line ) {
my ( $ interface , $ hosts ) = split_line 1 , 2 , 'ecn file entry' ;
2010-08-31 01:47:45 +02:00
fatal_error "Unknown interface ($interface)" unless known_interface $ interface ;
2009-02-22 18:30:14 +01:00
$ interfaces { $ interface } = 1 ;
$ hosts = ALLIP if $ hosts eq '-' ;
for my $ host ( split_list $ hosts , 'address' ) {
validate_host ( $ host , 1 ) ;
push @ hosts , [ $ interface , $ host ] ;
}
}
if ( @ hosts ) {
my @ interfaces = ( keys % interfaces ) ;
progress_message "$doing ECN control on @interfaces..." ;
for my $ interface ( @ interfaces ) {
my $ chainref = ensure_chain 'mangle' , ecn_chain ( $ interface ) ;
2009-11-06 22:10:19 +01:00
add_jump $ mangle_table - > { POSTROUTING } , $ chainref , 0 , "-p tcp " . match_dest_dev ( $ interface ) ;
add_jump $ mangle_table - > { OUTPUT } , $ chainref , 0 , "-p tcp " . match_dest_dev ( $ interface ) ;
2009-02-22 18:30:14 +01:00
}
for my $ host ( @ hosts ) {
add_rule $ mangle_table - > { ecn_chain $ host - > [ 0 ] } , join ( '' , '-p tcp ' , match_dest_net ( $ host - > [ 1 ] ) , ' -j ECN --ecn-tcp-remove' ) ;
}
}
}
}
sub add_rule_pair ( $$$$ ) {
my ( $ chainref , $ predicate , $ target , $ level ) = @ _ ;
log_rule ( $ level , $ chainref , "\U$target" , $ predicate ) if defined $ level && $ level ne '' ;
2010-01-16 18:53:53 +01:00
add_jump ( $ chainref , $ target , 0 , $ predicate ) ;
2009-02-22 18:30:14 +01:00
}
sub setup_blacklist () {
2010-09-16 18:40:28 +02:00
my $ zones = find_zones_by_option 'blacklist' , 'in' ;
my $ zones1 = find_zones_by_option 'blacklist' , 'out' ;
2009-02-22 18:30:14 +01:00
my $ chainref ;
2010-09-16 18:40:28 +02:00
my $ chainref1 ;
2009-02-22 18:30:14 +01:00
my ( $ level , $ disposition ) = @ config { 'BLACKLIST_LOGLEVEL' , 'BLACKLIST_DISPOSITION' } ;
2011-06-04 17:45:23 +02:00
my $ audit = $ disposition =~ /^A_/ ;
2011-05-31 01:37:56 +02:00
my $ target = $ disposition eq 'REJECT' ? 'reject' : $ disposition ;
my $ orig_target = $ target ;
2010-03-21 15:24:29 +01:00
#
2010-09-16 18:40:28 +02:00
# We go ahead and generate the blacklist chains and jump to them, even if they turn out to be empty. That is necessary
2010-03-21 15:24:29 +01:00
# for 'refresh' to work properly.
#
2010-09-16 18:40:28 +02:00
if ( @$ zones || @$ zones1 ) {
$ chainref = dont_delete new_standard_chain 'blacklst' if @$ zones ;
$ chainref1 = dont_delete new_standard_chain 'blackout' if @$ zones1 ;
2009-02-22 18:30:14 +01:00
2011-05-22 00:02:04 +02:00
if ( defined $ level && $ level ne '' ) {
2009-02-22 18:30:14 +01:00
my $ logchainref = new_standard_chain 'blacklog' ;
2011-06-04 17:45:23 +02:00
$ target =~ s/A_// ;
$ target = 'reject' if $ target eq 'REJECT' ;
2009-02-22 18:30:14 +01:00
log_rule_limit ( $ level , $ logchainref , 'blacklst' , $ disposition , "$globals{LOGLIMIT}" , '' , 'add' , '' ) ;
2011-05-23 02:42:50 +02:00
if ( $ audit ) {
if ( $ config { FAKE_AUDIT } ) {
add_rule ( $ logchainref , '-j AUDIT -m comment --comment "--type ' . lc $ target . '"' ) ;
} else {
add_rule ( $ logchainref , '-j AUDIT --type ' . lc $ target ) ;
}
}
2011-05-21 18:25:58 +02:00
2010-01-16 18:53:53 +01:00
add_jump $ logchainref , $ target , 1 ;
2009-02-22 18:30:14 +01:00
$ target = 'blacklog' ;
2011-05-22 00:02:04 +02:00
} elsif ( $ audit ) {
require_capability 'AUDIT_TARGET' , "BLACKLIST_DISPOSITION=$disposition" , 's' ;
2011-06-04 17:45:23 +02:00
$ target = verify_audit ( $ disposition ) ;
2011-05-22 00:02:04 +02:00
}
2009-02-22 18:30:14 +01:00
}
BLACKLIST:
{
if ( my $ fn = open_file 'blacklist' ) {
my $ first_entry = 1 ;
first_entry "$doing $fn..." ;
while ( read_a_line ) {
if ( $ first_entry ) {
2010-09-16 18:40:28 +02:00
unless ( @$ zones || @$ zones1 ) {
warning_message qq( The entries in $fn have been ignored because there are no 'blacklist' zones ) ;
2009-02-22 18:30:14 +01:00
close_file ;
last BLACKLIST ;
}
$ first_entry = 0 ;
}
2010-09-16 18:40:28 +02:00
my ( $ networks , $ protocol , $ ports , $ options ) = split_line 1 , 4 , 'blacklist file' ;
2010-03-19 18:01:02 +01:00
2011-06-04 17:45:23 +02:00
if ( $ options eq '-' ) {
$ options = 'src' ;
} elsif ( $ options eq 'audit' ) {
$ options = 'audit,src' ;
}
2009-02-22 18:30:14 +01:00
2011-05-21 18:25:58 +02:00
my ( $ to , $ from , $ whitelist , $ auditone ) = ( 0 , 0 , 0 , 0 ) ;
2009-02-22 18:30:14 +01:00
2011-05-18 17:30:01 +02:00
my @ options = split_list $ options , 'option' ;
for ( @ options ) {
$ whitelist + + if $ _ eq 'whitelist' ;
2011-05-21 18:25:58 +02:00
$ auditone + + if $ _ eq 'audit' ;
2011-05-18 17:30:01 +02:00
}
warning_message "Duplicate 'whitelist' option ignored" if $ whitelist > 1 ;
my $ tgt = $ whitelist ? 'RETURN' : $ target ;
2011-05-21 18:25:58 +02:00
if ( $ auditone ) {
fatal_error "'audit' not allowed in whitelist entries" if $ whitelist ;
if ( $ audit ) {
warning_message "Superfluous 'audit' option ignored" ;
} else {
warning_message "Duplicate 'audit' option ignored" if $ auditone > 1 ;
2011-05-31 01:37:56 +02:00
2011-06-04 17:45:23 +02:00
$ tgt = verify_audit ( 'A_' . $ target , $ orig_target , $ target ) ;
2011-05-21 18:25:58 +02:00
}
}
2011-05-18 17:30:01 +02:00
for ( @ options ) {
2011-05-18 20:13:03 +02:00
if ( $ _ =~ /^(?:src|from)$/ ) {
2010-09-16 18:40:28 +02:00
if ( $ from + + ) {
warning_message "Duplicate 'src' ignored" ;
} else {
if ( @$ zones ) {
expand_rule (
$ chainref ,
NO_RESTRICT ,
do_proto ( $ protocol , $ ports , '' ) ,
$ networks ,
'' ,
'' ,
2011-05-18 17:30:01 +02:00
$ tgt ,
2010-09-16 18:40:28 +02:00
'' ,
2011-05-18 17:30:01 +02:00
$ tgt ,
2010-09-16 18:40:28 +02:00
'' ) ;
} else {
2010-09-17 21:35:34 +02:00
warning_message '"src" entry ignored because there are no "blacklist in" zones' ;
2010-09-16 18:40:28 +02:00
}
}
} elsif ( $ _ =~ /^(?:dst|to)$/ ) {
if ( $ to + + ) {
warning_message "Duplicate 'dst' ignored" ;
} else {
if ( @$ zones1 ) {
expand_rule (
$ chainref1 ,
NO_RESTRICT ,
do_proto ( $ protocol , $ ports , '' ) ,
'' ,
$ networks ,
'' ,
2011-05-18 17:30:01 +02:00
$ tgt ,
2010-09-16 18:40:28 +02:00
'' ,
2011-05-18 17:30:01 +02:00
$ tgt ,
2010-09-16 18:40:28 +02:00
'' ) ;
} else {
2010-09-17 21:35:34 +02:00
warning_message '"dst" entry ignored because there are no "blacklist out" zones' ;
2010-09-16 18:40:28 +02:00
}
}
2011-05-18 20:13:03 +02:00
} else {
2011-05-21 18:25:58 +02:00
fatal_error "Invalid blacklist option($_)" unless $ _ eq 'whitelist' || $ _ eq 'audit' ;
2010-09-16 18:40:28 +02:00
}
}
2009-02-22 18:30:14 +01:00
2010-09-16 18:40:28 +02:00
progress_message " \"$currentline\" added to blacklist" ;
2009-02-22 18:30:14 +01:00
}
2010-09-16 18:40:28 +02:00
warning_message q( There are interfaces or zones with the 'blacklist' option but the 'blacklist' file is empty ) if $ first_entry && @$ zones ;
} elsif ( @$ zones || @$ zones1 ) {
warning_message q( There are interfaces or zones with the 'blacklist' option, but the 'blacklist' file is either missing or has zero size ) ;
2009-02-22 18:30:14 +01:00
}
}
}
sub process_routestopped () {
2010-09-28 19:48:44 +02:00
if ( my $ fn = open_file 'routestopped' ) {
my ( @ allhosts , % source , % dest , % notrack , @ rule ) ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ seq = 0 ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
first_entry "$doing $fn..." ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
while ( read_a_line ) {
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my ( $ interface , $ hosts , $ options , $ proto , $ ports , $ sports ) = split_line 1 , 6 , 'routestopped file' ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ interfaceref ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
fatal_error "Unknown interface ($interface)" unless $ interfaceref = known_interface $ interface ;
$ hosts = ALLIP unless $ hosts && $ hosts ne '-' ;
2010-05-03 21:31:11 +02:00
2010-09-28 19:48:44 +02:00
my $ routeback = 0 ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my @ hosts ;
2010-05-03 21:31:11 +02:00
2010-09-28 19:48:44 +02:00
$ seq + + ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ rule = do_proto ( $ proto , $ ports , $ sports , 0 ) ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
for my $ host ( split /,/ , $ hosts ) {
fatal_error "Ipsets not allowed with SAVE_IPSETS=Yes" if $ host =~ /^!?\+/ && $ config { SAVE_IPSETS } ;
validate_host $ host , 1 ;
push @ hosts , "$interface|$host|$seq" ;
push @ rule , $ rule ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
unless ( $ options eq '-' ) {
for my $ option ( split /,/ , $ options ) {
if ( $ option eq 'routeback' ) {
if ( $ routeback ) {
warning_message "Duplicate 'routeback' option ignored" ;
} else {
$ routeback = 1 ;
}
} elsif ( $ option eq 'source' ) {
for my $ host ( split /,/ , $ hosts ) {
$ source { "$interface|$host|$seq" } = 1 ;
}
} elsif ( $ option eq 'dest' ) {
for my $ host ( split /,/ , $ hosts ) {
$ dest { "$interface|$host|$seq" } = 1 ;
}
} elsif ( $ option eq 'notrack' ) {
for my $ host ( split /,/ , $ hosts ) {
$ notrack { "$interface|$host|$seq" } = 1 ;
}
2009-02-22 18:30:14 +01:00
} else {
2010-09-28 19:48:44 +02:00
warning_message "Unknown routestopped option ( $option ) ignored" unless $ option eq 'critical' ;
warning_message "The 'critical' option is no longer supported (or needed)" ;
2009-02-22 18:30:14 +01:00
}
}
}
2010-09-28 19:48:44 +02:00
if ( $ routeback || $ interfaceref - > { options } { routeback } ) {
my $ chainref = $ filter_table - > { FORWARD } ;
2010-05-03 21:31:11 +02:00
2010-09-28 19:48:44 +02:00
for my $ host ( split /,/ , $ hosts ) {
add_rule ( $ chainref ,
match_source_dev ( $ interface ) .
match_dest_dev ( $ interface ) .
match_source_net ( $ host ) .
match_dest_net ( $ host ) ) ;
clearrule ;
}
2010-05-03 21:31:11 +02:00
}
2010-09-28 19:48:44 +02:00
push @ allhosts , @ hosts ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
for my $ host ( @ allhosts ) {
my ( $ interface , $ h , $ seq ) = split /\|/ , $ host ;
my $ source = match_source_net $ h ;
my $ dest = match_dest_net $ h ;
my $ sourcei = match_source_dev $ interface ;
my $ desti = match_dest_dev $ interface ;
my $ rule = shift @ rule ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
add_rule $ filter_table - > { INPUT } , "$sourcei $source $rule -j ACCEPT" , 1 ;
add_rule $ filter_table - > { OUTPUT } , "$desti $dest $rule -j ACCEPT" , 1 unless $ config { ADMINISABSENTMINDED } ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ matched = 0 ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ source { $ host } ) {
add_rule $ filter_table - > { FORWARD } , "$sourcei $source $rule -j ACCEPT" , 1 ;
$ matched = 1 ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ dest { $ host } ) {
add_rule $ filter_table - > { FORWARD } , "$desti $dest $rule -j ACCEPT" , 1 ;
$ matched = 1 ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ notrack { $ host } ) {
add_rule $ raw_table - > { PREROUTING } , "$sourcei $source $rule -j NOTRACK" , 1 ;
add_rule $ raw_table - > { OUTPUT } , "$desti $dest $rule -j NOTRACK" , 1 ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
unless ( $ matched ) {
for my $ host1 ( @ allhosts ) {
unless ( $ host eq $ host1 ) {
my ( $ interface1 , $ h1 , $ seq1 ) = split /\|/ , $ host1 ;
my $ dest1 = match_dest_net $ h1 ;
my $ desti1 = match_dest_dev $ interface1 ;
add_rule $ filter_table - > { FORWARD } , "$sourcei $desti1 $source $dest1 $rule -j ACCEPT" , 1 ;
clearrule ;
}
2009-02-22 18:30:14 +01:00
}
}
}
}
}
sub setup_mss () ;
sub add_common_rules () {
my $ interface ;
my $ chainref ;
my $ target ;
2011-06-09 18:57:45 +02:00
my $ target1 ;
2009-02-22 18:30:14 +01:00
my $ rule ;
my $ list ;
my $ chain ;
2011-05-26 22:38:44 +02:00
my $ dynamicref ;
2009-02-22 18:30:14 +01:00
2011-05-26 22:38:44 +02:00
my $ state = $ config { BLACKLISTNEWONLY } ? $ globals { UNTRACKED } ? "$globals{STATEMATCH} NEW,INVALID,UNTRACKED " : "$globals{STATEMATCH} NEW,INVALID " : '' ;
2010-01-16 18:53:53 +01:00
my $ level = $ config { BLACKLIST_LOGLEVEL } ;
2011-05-24 05:59:33 +02:00
my $ rejectref = $ filter_table - > { reject } ;
2009-02-22 18:30:14 +01:00
2010-01-16 18:53:53 +01:00
if ( $ config { DYNAMIC_BLACKLIST } ) {
add_rule_pair dont_delete ( new_standard_chain ( 'logdrop' ) ) , ' ' , 'DROP' , $ level ;
add_rule_pair dont_delete ( new_standard_chain ( 'logreject' ) ) , ' ' , 'reject' , $ level ;
2011-05-26 22:38:44 +02:00
$ dynamicref = dont_optimize ( new_standard_chain ( 'dynamic' ) ) ;
add_jump $ filter_table - > { INPUT } , $ dynamicref , 0 , $ state ;
add_commands ( $ dynamicref , '[ -f ${VARDIR}/.dynamic ] && cat ${VARDIR}/.dynamic >&3' ) ;
2010-01-16 18:53:53 +01:00
}
2009-02-22 18:30:14 +01:00
setup_mss ;
2011-06-09 18:57:45 +02:00
add_rule ( $ filter_table - > { OUTPUT } , "$globals{STATEMATCH} ESTABLISHED,RELATED -j ACCEPT" ) if ( $ config { FASTACCEPT } ) ;
2011-05-26 22:38:44 +02:00
2011-05-28 04:42:09 +02:00
my $ policy = $ config { SFILTER_DISPOSITION } ;
$ level = $ config { SFILTER_LOG_LEVEL } ;
2011-05-26 22:38:44 +02:00
my $ audit = $ policy =~ s/^A_// ;
2011-06-09 18:57:45 +02:00
my $ ipsec = have_ipsec ? '-m policy --pol none --dir in ' : '' ;
2011-05-26 22:38:44 +02:00
2011-06-09 18:57:45 +02:00
if ( $ level || $ audit || $ ipsec ) {
2011-05-28 04:42:09 +02:00
$ chainref = new_standard_chain 'sfilter' ;
2011-05-26 22:38:44 +02:00
log_rule $ level , $ chainref , $ policy , '' if $ level ne '' ;
add_rule ( $ chainref , '-j AUDIT --type ' . lc $ policy ) if $ audit ;
add_jump $ chainref , $ policy eq 'REJECT' ? 'reject' : $ policy , 1 ;
2011-05-28 04:42:09 +02:00
$ target = 'sfilter' ;
2011-06-09 18:57:45 +02:00
if ( $ ipsec ) {
$ chainref = new_standard_chain 'sfilter1' ;
add_rule ( $ chainref , '-m policy --pol ipsec --dir out -j RETURN' ) ;
log_rule $ level , $ chainref , $ policy , '' if $ level ne '' ;
add_rule ( $ chainref , '-j AUDIT --type ' . lc $ policy ) if $ audit ;
add_jump $ chainref , $ policy eq 'REJECT' ? 'reject' : $ policy , 1 ;
$ target1 = 'sfilter1' ;
}
2011-05-26 22:38:44 +02:00
} elsif ( ( $ target = $ policy ) eq 'REJECT' ) {
$ target = 'reject' ;
2009-02-22 18:30:14 +01:00
}
2011-06-09 18:57:45 +02:00
$ target1 = $ target unless $ target1 ;
2010-07-01 05:35:46 +02:00
for $ interface ( grep $ _ ne '%vserver%' , all_interfaces ) {
2009-02-22 18:30:14 +01:00
ensure_chain ( 'filter' , $ _ ) for first_chains ( $ interface ) , output_chain ( $ interface ) ;
2011-05-26 22:38:44 +02:00
my $ interfaceref = find_interface $ interface ;
unless ( $ interfaceref - > { options } { ignore } ) {
my @ filters = @ { $ interfaceref - > { filter } } ;
$ chainref = $ filter_table - > { forward_chain $ interface } ;
if ( @ filters ) {
2011-06-10 01:54:32 +02:00
add_jump ( $ chainref , $ target1 , ! $ ipsec , match_source_net ( $ _ ) . $ ipsec ) , $ chainref - > { filtered } + + for @ filters ;
2011-06-09 18:57:45 +02:00
} elsif ( $ interfaceref - > { bridge } eq $ interface ) {
2011-06-10 01:54:32 +02:00
add_jump ( $ chainref , $ target1 , ! $ ipsec , match_dest_dev ( $ interface ) . $ ipsec ) , $ chainref - > { filtered } + + unless $ interfaceref - > { options } { routeback } || $ interfaceref - > { options } { routefilter } ;
2011-06-09 18:57:45 +02:00
}
add_rule ( $ chainref , "$globals{STATEMATCH} ESTABLISHED,RELATED -j ACCEPT" ) , $ chainref - > { filtered } + + if $ config { FASTACCEPT } ;
add_jump ( $ chainref , $ dynamicref , 0 , $ state ) , $ chainref - > { filtered } + + if $ dynamicref ;
$ chainref = $ filter_table - > { input_chain $ interface } ;
if ( @ filters ) {
add_jump ( $ chainref , $ target , 1 , match_source_net ( $ _ ) . $ ipsec ) , $ chainref - > { filtered } + + for @ filters ;
2011-05-26 22:38:44 +02:00
} elsif ( $ interfaceref - > { bridge } eq $ interface ) {
2011-06-09 16:27:06 +02:00
add_jump ( $ chainref , $ target , 1 , match_dest_dev ( $ interface ) . $ ipsec ) , $ chainref - > { filtered } + + unless $ interfaceref - > { options } { routeback } || $ interfaceref - > { options } { routefilter } ;
2011-05-26 22:38:44 +02:00
}
2011-06-09 18:57:45 +02:00
add_rule ( $ chainref , "$globals{STATEMATCH} ESTABLISHED,RELATED -j ACCEPT" ) , $ chainref - > { filtered } + + if $ config { FASTACCEPT } ;
2011-05-26 22:38:44 +02:00
add_jump ( $ chainref , $ dynamicref , 0 , $ state ) , $ chainref - > { filtered } + + if $ dynamicref ;
}
2009-02-22 18:30:14 +01:00
}
2011-05-28 04:56:54 +02:00
#
2011-06-10 02:09:53 +02:00
# Delete 'sfilter' chains unless there are referenced to them
2011-05-28 04:56:54 +02:00
#
2011-06-10 02:09:53 +02:00
for ( qw/sfilter sfilter1/ ) {
if ( $ chainref = $ filter_table - > { $ _ } ) {
$ chainref - > { referenced } = 0 unless keys % { $ chainref - > { references } } ;
}
}
2011-05-28 04:56:54 +02:00
2009-02-22 18:30:14 +01:00
run_user_exit1 'initdone' ;
setup_blacklist ;
$ list = find_hosts_by_option 'nosmurfs' ;
2010-02-04 00:03:15 +01:00
if ( @$ list ) {
progress_message2 'Adding Anti-smurf Rules' ;
$ chainref = new_standard_chain 'smurfs' ;
2010-06-07 16:30:56 +02:00
2011-05-22 00:02:04 +02:00
my $ smurfdest = $ config { SMURF_DISPOSITION } ;
2010-02-04 00:03:15 +01:00
if ( defined $ config { SMURF_LOG_LEVEL } && $ config { SMURF_LOG_LEVEL } ne '' ) {
2011-05-22 00:02:04 +02:00
my $ smurfref = new_chain ( 'filter' , 'smurflog' ) ;
2010-06-07 16:30:56 +02:00
2010-02-04 00:03:15 +01:00
log_rule_limit ( $ config { SMURF_LOG_LEVEL } ,
$ smurfref ,
'smurfs' ,
'DROP' ,
$ globals { LOGLIMIT } ,
2010-06-07 16:30:56 +02:00
'' ,
2010-02-04 00:03:15 +01:00
'add' ,
'' ) ;
2011-05-23 02:42:50 +02:00
if ( $ smurfdest eq 'A_DROP' ) {
if ( $ config { FAKE_AUDIT } ) {
add_rule ( $ smurfref , '-j AUDIT -m comment --comment "--type drop"' ) ;
} else {
add_rule ( $ smurfref , '-j AUDIT --type drop' ) ;
}
}
2010-02-04 00:03:15 +01:00
add_rule ( $ smurfref , '-j DROP' ) ;
2011-05-22 00:02:04 +02:00
$ smurfdest = 'smurflog' ;
2010-02-04 00:03:15 +01:00
} else {
2011-05-22 00:02:04 +02:00
verify_audit ( $ smurfdest ) if $ smurfdest eq 'A_DROP' ;
2010-02-04 00:03:15 +01:00
}
if ( have_capability ( 'ADDRTYPE' ) ) {
2010-02-07 17:43:31 +01:00
if ( $ family == F_IPV4 ) {
add_rule $ chainref , '-s 0.0.0.0 -j RETURN' ;
} else {
2010-02-08 16:12:58 +01:00
add_rule $ chainref , '-s :: -j RETURN' ;
2010-02-07 17:43:31 +01:00
}
2010-02-04 00:03:15 +01:00
add_jump ( $ chainref , $ smurfdest , 1 , '-m addrtype --src-type BROADCAST ' ) ;
} else {
if ( $ family == F_IPV4 ) {
add_commands $ chainref , 'for address in $ALL_BCASTS; do' ;
} else {
add_commands $ chainref , 'for address in $ALL_ACASTS; do' ;
}
2010-06-07 16:30:56 +02:00
2010-02-04 00:03:15 +01:00
incr_cmd_level $ chainref ;
add_jump ( $ chainref , $ smurfdest , 1 , '-s $address ' ) ;
decr_cmd_level $ chainref ;
add_commands $ chainref , 'done' ;
}
2009-02-22 18:30:14 +01:00
if ( $ family == F_IPV4 ) {
2010-02-04 00:03:15 +01:00
add_jump ( $ chainref , $ smurfdest , 1 , '-s 224.0.0.0/4 ' ) ;
2009-02-22 18:30:14 +01:00
} else {
2010-07-16 19:06:29 +02:00
add_jump ( $ chainref , $ smurfdest , 1 , '-s ' . IPv6_MULTICAST . ' ' ) ;
2009-02-22 18:30:14 +01:00
}
2010-09-17 16:58:21 +02:00
my $ state = $ globals { UNTRACKED } ? '-m state --state NEW,INVALID,UNTRACKED ' : "$globals{STATEMATCH} NEW,INVALID " ;
2009-02-22 18:30:14 +01:00
2010-02-04 00:03:15 +01:00
for my $ hostref ( @$ list ) {
$ interface = $ hostref - > [ 0 ] ;
my $ ipsec = $ hostref - > [ 1 ] ;
my $ policy = have_ipsec ? "-m policy --pol $ipsec --dir in " : '' ;
my $ target = source_exclusion ( $ hostref - > [ 3 ] , $ chainref ) ;
for $ chain ( first_chains $ interface ) {
2010-09-17 16:58:21 +02:00
add_jump $ filter_table - > { $ chain } , $ target , 0 , join ( '' , $ state , match_source_net ( $ hostref - > [ 2 ] ) , $ policy ) ;
2010-02-04 00:03:15 +01:00
}
set_interface_option $ interface , 'use_input_chain' , 1 ;
set_interface_option $ interface , 'use_forward_chain' , 1 ;
}
2009-02-22 18:30:14 +01:00
}
2010-01-25 16:56:16 +01:00
if ( have_capability ( 'ADDRTYPE' ) ) {
2009-02-22 18:30:14 +01:00
add_rule $ rejectref , '-m addrtype --src-type BROADCAST -j DROP' ;
} else {
if ( $ family == F_IPV4 ) {
2009-07-07 03:38:39 +02:00
add_commands $ rejectref , 'for address in $ALL_BCASTS; do' ;
2009-02-22 18:30:14 +01:00
} else {
2009-07-07 03:38:39 +02:00
add_commands $ rejectref , 'for address in $ALL_ACASTS; do' ;
2009-02-22 18:30:14 +01:00
}
incr_cmd_level $ rejectref ;
add_rule $ rejectref , '-d $address -j DROP' ;
decr_cmd_level $ rejectref ;
2009-07-07 03:38:39 +02:00
add_commands $ rejectref , 'done' ;
2009-02-22 18:30:14 +01:00
}
if ( $ family == F_IPV4 ) {
add_rule $ rejectref , '-s 224.0.0.0/4 -j DROP' ;
} else {
2010-07-16 19:06:29 +02:00
add_rule $ rejectref , '-s ' . IPv6_MULTICAST . ' -j DROP' ;
2009-02-22 18:30:14 +01:00
}
add_rule $ rejectref , '-p 2 -j DROP' ;
add_rule $ rejectref , '-p 6 -j REJECT --reject-with tcp-reset' ;
2010-01-25 16:56:16 +01:00
if ( have_capability ( 'ENHANCED_REJECT' ) ) {
2009-02-22 18:30:14 +01:00
add_rule $ rejectref , '-p 17 -j REJECT' ;
if ( $ family == F_IPV4 ) {
add_rule $ rejectref , '-p 1 -j REJECT --reject-with icmp-host-unreachable' ;
add_rule $ rejectref , '-j REJECT --reject-with icmp-host-prohibited' ;
} else {
add_rule $ rejectref , '-p 58 -j REJECT --reject-with icmp6-addr-unreachable' ;
2009-08-20 23:32:15 +02:00
add_rule $ rejectref , '-j REJECT --reject-with icmp6-adm-prohibited' ;
2009-02-22 18:30:14 +01:00
}
} else {
add_rule $ rejectref , '-j REJECT' ;
}
$ list = find_interfaces_by_option 'dhcp' ;
if ( @$ list ) {
progress_message2 'Adding rules for DHCP' ;
my $ ports = $ family == F_IPV4 ? '67:68' : '546:547' ;
for $ interface ( @$ list ) {
set_interface_option $ interface , 'use_input_chain' , 1 ;
set_interface_option $ interface , 'use_forward_chain' , 1 ;
for $ chain ( input_chain $ interface , output_chain $ interface ) {
add_rule $ filter_table - > { $ chain } , "-p udp --dport $ports -j ACCEPT" ;
}
2010-06-07 16:30:56 +02:00
add_rule ( $ filter_table - > { forward_chain $ interface } ,
2009-11-06 22:10:19 +01:00
"-p udp " .
match_dest_dev ( $ interface ) .
"--dport $ports -j ACCEPT" )
if get_interface_option ( $ interface , 'bridge' ) ;
2009-02-22 18:30:14 +01:00
}
}
$ list = find_hosts_by_option 'tcpflags' ;
if ( @$ list ) {
2011-05-21 18:25:58 +02:00
my $ level = $ config { TCP_FLAGS_LOG_LEVEL } ;
my $ disposition = $ config { TCP_FLAGS_DISPOSITION } ;
2011-05-22 00:02:04 +02:00
my $ audit = $ disposition =~ /^A_/ ;
2009-02-22 18:30:14 +01:00
progress_message2 "$doing TCP Flags filtering..." ;
$ chainref = new_standard_chain 'tcpflags' ;
2011-05-22 00:02:04 +02:00
if ( $ level ) {
2009-02-22 18:30:14 +01:00
my $ logflagsref = new_standard_chain 'logflags' ;
2011-05-22 00:02:04 +02:00
my $ savelogparms = $ globals { LOGPARMS } ;
2009-02-22 18:30:14 +01:00
2011-05-22 00:02:04 +02:00
$ globals { LOGPARMS } = "$globals{LOGPARMS}--log-ip-options " ;
2009-02-22 18:30:14 +01:00
2011-05-22 00:02:04 +02:00
log_rule $ level , $ logflagsref , $ config { TCP_FLAGS_DISPOSITION } , '' ;
$ globals { LOGPARMS } = $ savelogparms ;
2009-02-22 18:30:14 +01:00
2011-05-22 00:02:04 +02:00
if ( $ audit ) {
$ disposition =~ s/^A_// ;
2011-05-23 02:42:50 +02:00
if ( $ config { FAKE_AUDIT } ) {
add_rule ( $ logflagsref , '-j AUDIT -m comment --comment "--type ' . lc $ disposition . '"' ) ;
} else {
add_rule ( $ logflagsref , '-j AUDIT --type ' . lc $ disposition ) ;
}
2011-05-21 18:25:58 +02:00
}
2011-05-22 00:02:04 +02:00
if ( $ disposition eq 'REJECT' ) {
2009-02-22 18:30:14 +01:00
add_rule $ logflagsref , '-p 6 -j REJECT --reject-with tcp-reset' ;
} else {
2011-05-22 00:02:04 +02:00
add_rule $ logflagsref , "-j $disposition" ;
2009-02-22 18:30:14 +01:00
}
$ disposition = 'logflags' ;
2011-05-22 00:02:04 +02:00
} elsif ( $ audit ) {
require_capability ( 'AUDIT_TARGET' , "TCP_FLAGS_DISPOSITION=$disposition" , 's' ) ;
verify_audit ( $ disposition ) ;
2009-02-22 18:30:14 +01:00
}
2010-01-16 18:53:53 +01:00
add_jump $ chainref , $ disposition , 1 , '-p tcp --tcp-flags ALL FIN,URG,PSH ' ;
add_jump $ chainref , $ disposition , 1 , '-p tcp --tcp-flags ALL NONE ' ;
add_jump $ chainref , $ disposition , 1 , '-p tcp --tcp-flags SYN,RST SYN,RST ' ;
add_jump $ chainref , $ disposition , 1 , '-p tcp --tcp-flags SYN,FIN SYN,FIN ' ;
add_jump $ chainref , $ disposition , 1 , '-p tcp --syn --sport 0 ' ;
2009-02-22 18:30:14 +01:00
for my $ hostref ( @$ list ) {
my $ interface = $ hostref - > [ 0 ] ;
my $ target = source_exclusion ( $ hostref - > [ 3 ] , $ chainref ) ;
2010-01-25 17:13:22 +01:00
my $ policy = have_ipsec ? "-m policy --pol $hostref->[1] --dir in " : '' ;
2009-02-22 18:30:14 +01:00
for $ chain ( first_chains $ interface ) {
add_jump $ filter_table - > { $ chain } , $ target , 0 , join ( '' , '-p tcp ' , match_source_net ( $ hostref - > [ 2 ] ) , $ policy ) ;
}
set_interface_option $ interface , 'use_input_chain' , 1 ;
set_interface_option $ interface , 'use_forward_chain' , 1 ;
}
}
if ( $ family == F_IPV4 ) {
2009-06-15 22:34:35 +02:00
my $ announced = 0 ;
2009-02-22 18:30:14 +01:00
$ list = find_interfaces_by_option 'upnp' ;
if ( @$ list ) {
progress_message2 "$doing UPnP" ;
2010-06-06 22:10:28 +02:00
$ chainref = dont_optimize new_nat_chain ( 'UPnP' ) ;
2010-06-07 16:18:21 +02:00
add_commands ( $ chainref , '[ -s /${VARDIR}/.UPnP ] && cat ${VARDIR}/.UPnP >&3' ) ;
2009-02-22 18:30:14 +01:00
2009-06-15 22:34:35 +02:00
$ announced = 1 ;
2009-02-22 18:30:14 +01:00
for $ interface ( @$ list ) {
2010-01-16 18:53:53 +01:00
add_jump $ nat_table - > { PREROUTING } , 'UPnP' , 0 , match_source_dev ( $ interface ) ;
2009-02-22 18:30:14 +01:00
}
}
2009-06-15 22:34:35 +02:00
$ list = find_interfaces_by_option 'upnpclient' ;
if ( @$ list ) {
progress_message2 "$doing UPnP" unless $ announced ;
for $ interface ( @$ list ) {
my $ chainref = $ filter_table - > { input_chain $ interface } ;
2010-08-28 23:18:48 +02:00
my $ base = uc chain_base get_physical $ interface ;
2009-06-15 22:34:35 +02:00
my $ variable = get_interface_gateway $ interface ;
2009-08-11 17:31:58 +02:00
if ( interface_is_optional $ interface ) {
2009-08-20 23:32:15 +02:00
add_commands ( $ chainref ,
2010-08-28 23:46:29 +02:00
qq( if [ -n "SW_\$${base}_IS_USABLE" -a -n "$variable" ]; then ) ,
2010-06-06 17:05:19 +02:00
' echo "-A ' . match_source_dev ( $ interface ) . qq( -s $variable -p udp -j ACCEPT" >&3 ) ,
2009-08-11 17:31:58 +02:00
qq( fi ) ) ;
} else {
2010-06-06 17:05:19 +02:00
add_rule ( $ chainref , match_source_dev ( $ interface ) . qq( -s $variable -p udp -j ACCEPT ) ) ;
2009-08-11 17:31:58 +02:00
}
2009-06-15 22:34:35 +02:00
}
}
2009-02-22 18:30:14 +01:00
}
setup_syn_flood_chains ;
}
my % maclist_targets = ( ACCEPT = > { target = > 'RETURN' , mangle = > 1 } ,
REJECT = > { target = > 'reject' , mangle = > 0 } ,
DROP = > { target = > 'DROP' , mangle = > 1 } ) ;
sub setup_mac_lists ( $ ) {
my $ phase = $ _ [ 0 ] ;
my % maclist_interfaces ;
my $ table = $ config { MACLIST_TABLE } ;
my $ maclist_hosts = find_hosts_by_option 'maclist' ;
my $ target = $ globals { MACLIST_TARGET } ;
my $ level = $ config { MACLIST_LOG_LEVEL } ;
my $ disposition = $ config { MACLIST_DISPOSITION } ;
2011-05-21 18:25:58 +02:00
my $ audit = $ disposition =~ /^A_/ ;
2009-02-22 18:30:14 +01:00
my $ ttl = $ config { MACLIST_TTL } ;
progress_message2 "$doing MAC Filtration -- Phase $phase..." ;
for my $ hostref ( @$ maclist_hosts ) {
$ maclist_interfaces { $ hostref - > [ 0 ] } = 1 ;
}
my @ maclist_interfaces = ( sort keys % maclist_interfaces ) ;
if ( $ phase == 1 ) {
for my $ interface ( @ maclist_interfaces ) {
my $ chainref = new_chain $ table , mac_chain $ interface ;
if ( $ family == F_IPV4 ) {
2009-08-20 23:32:15 +02:00
add_rule $ chainref , '-s 0.0.0.0 -d 255.255.255.255 -p udp --dport 67:68 -j RETURN'
2009-02-22 18:30:14 +01:00
if $ table eq 'mangle' && get_interface_option ( $ interface , 'dhcp' ) ;
} else {
#
# Accept any packet with a link-level source or destination address
#
add_rule $ chainref , '-s ff80::/10 -j RETURN' ;
add_rule $ chainref , '-d ff80::/10 -j RETURN' ;
#
# Accept Multicast
#
2010-07-16 19:06:29 +02:00
add_rule $ chainref , '-d ' . IPv6_MULTICAST . ' -j RETURN' ;
2009-02-22 18:30:14 +01:00
}
if ( $ ttl ) {
my $ chain1ref = new_chain $ table , macrecent_target $ interface ;
my $ chain = $ chainref - > { name } ;
add_rule $ chainref , "-m recent --rcheck --seconds $ttl --name $chain -j RETURN" ;
2010-01-16 18:53:53 +01:00
add_jump $ chainref , $ chain1ref , 0 ;
2009-02-22 18:30:14 +01:00
add_rule $ chainref , "-m recent --update --name $chain -j RETURN" ;
add_rule $ chainref , "-m recent --set --name $chain" ;
}
}
2010-09-28 19:48:44 +02:00
if ( my $ fn = open_file 'maclist' ) {
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
first_entry "$doing $fn..." ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
while ( read_a_line ) {
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my ( $ original_disposition , $ interface , $ mac , $ addresses ) = split_line1 3 , 4 , 'maclist file' ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ original_disposition eq 'COMMENT' ) {
process_comment ;
} else {
my ( $ disposition , $ level , $ remainder ) = split ( /:/ , $ original_disposition , 3 ) ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
fatal_error "Invalid DISPOSITION ($original_disposition)" if defined $ remainder || ! $ disposition ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ targetref = $ maclist_targets { $ disposition } ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
fatal_error "Invalid DISPOSITION ($original_disposition)" if ! $ targetref || ( ( $ table eq 'mangle' ) && ! $ targetref - > { mangle } ) ;
fatal_error "Unknown Interface ($interface)" unless known_interface ( $ interface ) ;
fatal_error "No hosts on $interface have the maclist option specified" unless $ maclist_interfaces { $ interface } ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
my $ chainref = $ chain_table { $ table } { ( $ ttl ? macrecent_target $ interface : mac_chain $ interface ) } ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
$ mac = '' unless $ mac && ( $ mac ne '-' ) ;
$ addresses = '' unless defined $ addresses && ( $ addresses ne '-' ) ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
fatal_error "You must specify a MAC address or an IP address" unless $ mac || $ addresses ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
$ mac = mac_match $ mac if $ mac ;
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ addresses ) {
for my $ address ( split ',' , $ addresses ) {
my $ source = match_source_net $ address ;
log_rule_limit $ level , $ chainref , mac_chain ( $ interface ) , $ disposition , '' , '' , 'add' , "${mac}${source}"
if defined $ level && $ level ne '' ;
2011-05-23 02:42:50 +02:00
if ( $ audit && $ disposition ne 'ACCEPT' ) {
if ( $ config { FAKE_AUDIT } ) {
add_rule ( $ chainref , '-j AUDIT -m comment --comment "--type ' . lc $ disposition . '"' ) ;
} else {
add_rule ( $ chainref , '-j AUDIT --type ' . lc $ disposition ) ;
}
}
2010-09-28 19:48:44 +02:00
add_jump $ chainref , $ targetref - > { target } , 0 , "${mac}${source}" ;
}
} else {
log_rule_limit $ level , $ chainref , mac_chain ( $ interface ) , $ disposition , '' , '' , 'add' , $ mac
2009-02-22 18:30:14 +01:00
if defined $ level && $ level ne '' ;
2011-05-23 02:42:50 +02:00
if ( $ audit && $ disposition ne 'ACCEPT' ) {
if ( $ config { FAKE_AUDIT } ) {
add_rule ( $ chainref , '-j AUDIT -m comment --comment "--type ' . lc $ disposition . '"' ) ;
} else {
add_rule ( $ chainref , '-j AUDIT --type ' . lc $ disposition ) ;
}
}
2010-09-28 19:48:44 +02:00
add_jump $ chainref , $ targetref - > { target } , 0 , "$mac" ;
2009-02-22 18:30:14 +01:00
}
2010-09-28 19:48:44 +02:00
progress_message " Maclist entry \"$currentline\" $done" ;
}
2009-02-22 18:30:14 +01:00
}
2010-09-28 19:48:44 +02:00
clear_comment ;
}
2009-02-22 18:30:14 +01:00
#
# Generate jumps from the input and forward chains
#
for my $ hostref ( @$ maclist_hosts ) {
my $ interface = $ hostref - > [ 0 ] ;
my $ ipsec = $ hostref - > [ 1 ] ;
2010-01-25 17:13:22 +01:00
my $ policy = have_ipsec ? "-m policy --pol $ipsec --dir in " : '' ;
2009-02-22 18:30:14 +01:00
my $ source = match_source_net $ hostref - > [ 2 ] ;
2010-09-17 16:58:21 +02:00
my $ state = $ globals { UNTRACKED } ? '-m state --state NEW,UNTRACKED' : "$globals{STATEMATCH} NEW" ;
2009-02-22 18:30:14 +01:00
if ( $ table eq 'filter' ) {
my $ chainref = source_exclusion ( $ hostref - > [ 3 ] , $ filter_table - > { mac_chain $ interface } ) ;
for my $ chain ( first_chains $ interface ) {
2010-09-17 16:58:21 +02:00
add_jump $ filter_table - > { $ chain } , $ chainref , 0 , "${source}${state} ${policy}" ;
2009-02-22 18:30:14 +01:00
}
set_interface_option $ interface , 'use_input_chain' , 1 ;
set_interface_option $ interface , 'use_forward_chain' , 1 ;
} else {
my $ chainref = source_exclusion ( $ hostref - > [ 3 ] , $ mangle_table - > { mac_chain $ interface } ) ;
2010-09-17 16:58:21 +02:00
add_jump $ mangle_table - > { PREROUTING } , $ chainref , 0 , match_source_dev ( $ interface ) . "${source}${state} ${policy}" ;
2009-02-22 18:30:14 +01:00
}
}
} else {
2009-09-10 23:56:23 +02:00
#
# Phase II
#
2009-02-22 18:30:14 +01:00
for my $ interface ( @ maclist_interfaces ) {
my $ chainref = $ chain_table { $ table } { ( $ ttl ? macrecent_target $ interface : mac_chain $ interface ) } ;
my $ chain = $ chainref - > { name } ;
if ( $ family == F_IPV4 ) {
if ( $ level ne '' || $ disposition ne 'ACCEPT' ) {
my $ variable = get_interface_addresses source_port_to_bridge ( $ interface ) ;
2010-01-25 16:56:16 +01:00
if ( have_capability ( 'ADDRTYPE' ) ) {
2009-02-22 18:30:14 +01:00
add_commands ( $ chainref ,
"for address in $variable; do" ,
2010-04-15 02:05:03 +02:00
" echo \"-A -s \$address -m addrtype --dst-type BROADCAST -j RETURN\" >&3" ,
" echo \"-A -s \$address -d 224.0.0.0/4 -j RETURN\" >&3" ,
2009-02-22 18:30:14 +01:00
'done' ) ;
} else {
my $ bridge = source_port_to_bridge ( $ interface ) ;
my $ bridgeref = find_interface ( $ bridge ) ;
add_commands ( $ chainref ,
"for address in $variable; do" ) ;
if ( $ bridgeref - > { broadcasts } ) {
for my $ address ( @ { $ bridgeref - > { broadcasts } } , '255.255.255.255' ) {
add_commands ( $ chainref ,
2010-04-15 02:05:03 +02:00
" echo \"-A -s \$address -d $address -j RETURN\" >&3" ) ;
2009-02-22 18:30:14 +01:00
}
} else {
my $ variable1 = get_interface_bcasts $ bridge ;
2009-08-20 23:32:15 +02:00
add_commands ( $ chainref ,
2009-02-22 18:30:14 +01:00
" for address1 in $variable1; do" ,
2010-04-15 02:05:03 +02:00
" echo \"-A -s \$address -d \$address1 -j RETURN\" >&3" ,
2009-02-22 18:30:14 +01:00
" done" ) ;
}
2009-07-07 03:38:39 +02:00
add_commands ( $ chainref
2010-04-15 02:05:03 +02:00
, " echo \"-A -s \$address -d 224.0.0.0/4 -j RETURN\" >&3" ,
2009-07-07 03:38:39 +02:00
, 'done' ) ;
2009-02-22 18:30:14 +01:00
}
}
}
run_user_exit2 ( 'maclog' , $ chainref ) ;
log_rule_limit $ level , $ chainref , $ chain , $ disposition , '' , '' , 'add' , '' if $ level ne '' ;
2010-01-16 18:53:53 +01:00
add_jump $ chainref , $ target , 0 ;
2009-02-22 18:30:14 +01:00
}
}
}
2010-12-15 21:57:55 +01:00
#
# Helper functions for generate_matrix()
#-----------------------------------------
#
# Return the target for rules from $zone to $zone1.
#
sub rules_target ( $$ ) {
my ( $ zone , $ zone1 ) = @ _ ;
my $ chain = rules_chain ( $ { zone } , $ { zone1 } ) ;
my $ chainref = $ filter_table - > { $ chain } ;
return $ chain if $ chainref && $ chainref - > { referenced } ;
return 'ACCEPT' if $ zone eq $ zone1 ;
assert ( $ chainref ) ;
if ( $ chainref - > { policy } ne 'CONTINUE' ) {
my $ policyref = $ filter_table - > { $ chainref - > { policychain } } ;
assert ( $ policyref ) ;
return $ policyref - > { name } if $ policyref ne $ chainref ;
return $ chainref - > { policy } eq 'REJECT' ? 'reject' : $ chainref - > { policy } ;
}
'' ; # CONTINUE policy
}
2010-07-01 05:35:46 +02:00
#
2010-07-07 15:43:07 +02:00
# Generate rules for one destination zone
2010-07-01 05:35:46 +02:00
#
2010-07-07 15:43:07 +02:00
sub generate_dest_rules ( $$$$ ) {
2010-07-01 05:35:46 +02:00
my ( $ chainref , $ chain , $ z2 , $ match ) = @ _ ;
my $ z2ref = find_zone ( $ z2 ) ;
my $ type2 = $ z2ref - > { type } ;
if ( $ type2 == VSERVER ) {
2010-07-09 02:11:27 +02:00
for my $ hostref ( @ { $ z2ref - > { hosts } { ip } { '%vserver%' } } ) {
2010-09-28 19:48:44 +02:00
my $ exclusion = dest_exclusion ( $ hostref - > { exclusions } , $ chain ) ;
2010-07-09 02:11:27 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
2010-09-27 20:16:18 +02:00
add_jump ( $ chainref ,
2010-07-09 02:11:27 +02:00
$ exclusion ,
0 ,
2010-09-27 20:16:18 +02:00
join ( '' , $ match , match_dest_net ( $ net ) ) )
2010-07-01 05:35:46 +02:00
}
}
} else {
add_jump ( $ chainref , $ chain , 0 , $ match ) ;
}
}
#
2010-07-09 02:45:18 +02:00
# Generate rules for one vserver source zone
2010-07-01 05:35:46 +02:00
#
2010-07-07 15:43:07 +02:00
sub generate_source_rules ( $$$$ ) {
2010-07-01 05:35:46 +02:00
my ( $ outchainref , $ z1 , $ z2 , $ match ) = @ _ ;
my $ chain = rules_target ( $ z1 , $ z2 ) ;
2010-09-27 20:16:18 +02:00
2010-07-01 05:35:46 +02:00
if ( $ chain ) {
#
# Not a CONTINUE policy with no rules
#
2010-07-09 02:11:27 +02:00
for my $ hostref ( @ { defined_zone ( $ z1 ) - > { hosts } { ip } { '%vserver%' } } ) {
my $ ipsec_match = match_ipsec_in $ z1 , $ hostref ;
my $ exclusion = source_exclusion ( $ hostref - > { exclusions } , $ chain ) ;
2010-09-27 20:16:18 +02:00
2010-07-09 02:11:27 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
generate_dest_rules ( $ outchainref ,
$ exclusion ,
2010-09-27 20:16:18 +02:00
$ z2 ,
2010-07-09 02:11:27 +02:00
join ( '' , match_source_net ( $ net ) , $ match , $ ipsec_match )
) ;
2010-09-27 20:16:18 +02:00
}
2010-07-01 05:35:46 +02:00
}
2010-09-27 20:16:18 +02:00
}
2010-07-01 05:35:46 +02:00
}
#
2010-09-28 19:48:44 +02:00
# Loopback traffic -- this is where we assemble the intra-firewall chains
2010-07-01 05:35:46 +02:00
#
sub handle_loopback_traffic () {
my @ zones = ( vserver_zones , firewall_zone ) ;
my $ natout = $ nat_table - > { OUTPUT } ;
my $ rulenum = 0 ;
my $ outchainref ;
my $ rule = '' ;
if ( @ zones > 1 ) {
$ outchainref = new_standard_chain 'loopback' ;
2010-07-03 19:53:25 +02:00
add_jump $ filter_table - > { OUTPUT } , $ outchainref , 0 , '-o lo ' ;
2010-07-01 05:35:46 +02:00
} else {
$ outchainref = $ filter_table - > { OUTPUT } ;
$ rule = '-o lo ' ;
}
for my $ z1 ( @ zones ) {
my $ z1ref = find_zone ( $ z1 ) ;
my $ type1 = $ z1ref - > { type } ;
my $ natref = $ nat_table - > { dnat_chain $ z1 } ;
if ( $ type1 == FIREWALL ) {
for my $ z2 ( @ zones ) {
my $ chain = rules_target ( $ z1 , $ z2 ) ;
2010-07-07 15:43:07 +02:00
generate_dest_rules ( $ outchainref , $ chain , $ z2 , $ rule ) if $ chain ;
2010-07-01 05:35:46 +02:00
}
} else {
for my $ z2 ( @ zones ) {
2010-07-07 15:43:07 +02:00
generate_source_rules ( $ outchainref , $ z1 , $ z2 , $ rule ) ;
2010-07-01 05:35:46 +02:00
}
}
if ( $ natref && $ natref - > { referenced } ) {
my $ source_hosts_ref = defined_zone ( $ z1 ) - > { hosts } ;
for my $ typeref ( values % { $ source_hosts_ref } ) {
for my $ hostref ( @ { $ typeref - > { '%vserver%' } } ) {
my $ exclusion = source_exclusion ( $ hostref - > { exclusions } , $ natref ) ;
2010-09-27 20:16:18 +02:00
2010-07-01 05:35:46 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
add_jump ( $ natout , $ exclusion , 0 , match_source_net ( $ net ) , 0 , $ rulenum + + ) ;
}
2010-09-27 20:16:18 +02:00
}
2010-07-01 05:35:46 +02:00
}
}
}
add_rule $ filter_table - > { INPUT } , '-i lo -j ACCEPT' ;
}
2009-02-22 18:30:14 +01:00
#
# Add jumps from the builtin chains to the interface-chains that are used by this configuration
#
sub add_interface_jumps {
2009-10-17 19:59:41 +02:00
our % input_jump_added ;
our % output_jump_added ;
our % forward_jump_added ;
2009-02-22 18:30:14 +01:00
#
# Add Nat jumps
#
for my $ interface ( @ _ ) {
addnatjump 'POSTROUTING' , snat_chain ( $ interface ) , match_dest_dev ( $ interface ) ;
}
addnatjump 'PREROUTING' , 'nat_in' , '' ;
addnatjump 'POSTROUTING' , 'nat_out' , '' ;
addnatjump 'PREROUTING' , 'dnat' , '' ;
2010-07-01 05:35:46 +02:00
for my $ interface ( grep $ _ ne '%vserver%' , @ _ ) {
2009-02-22 18:30:14 +01:00
addnatjump 'PREROUTING' , input_chain ( $ interface ) , match_source_dev ( $ interface ) ;
addnatjump 'POSTROUTING' , output_chain ( $ interface ) , match_dest_dev ( $ interface ) ;
addnatjump 'POSTROUTING' , masq_chain ( $ interface ) , match_dest_dev ( $ interface ) ;
}
#
# Add the jumps to the interface chains from filter FORWARD, INPUT, OUTPUT
#
2010-07-01 05:35:46 +02:00
for my $ interface ( grep $ _ ne '%vserver%' , @ _ ) {
2010-04-27 21:26:58 +02:00
my $ forwardref = $ filter_table - > { forward_chain $ interface } ;
my $ inputref = $ filter_table - > { input_chain $ interface } ;
my $ outputref = $ filter_table - > { output_chain $ interface } ;
my $ interfaceref = find_interface ( $ interface ) ;
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { options } { port } ) {
my $ bridge = $ interfaceref - > { bridge } ;
add_rule ( $ filter_table - > { forward_chain $ bridge } ,
match_source_dev ( $ interface , 1 ) . match_dest_dev ( $ interface , 1 ) . '-j ACCEPT'
) unless $ interfaceref - > { nets } || ! $ interfaceref - > { options } { bridge } ;
add_jump ( $ filter_table - > { forward_chain $ bridge } ,
$ forwardref ,
0 ,
match_source_dev ( $ interface , 1 )
) unless $ forward_jump_added { $ interface } || ! use_forward_chain $ interface , $ forwardref ;
add_jump ( $ filter_table - > { input_chain $ bridge } ,
$ inputref ,
0 ,
match_source_dev ( $ interface , 1 )
) unless $ input_jump_added { $ interface } || ! use_input_chain $ interface , $ inputref ;
unless ( $ output_jump_added { $ interface } || ! use_output_chain $ interface , $ outputref ) {
add_jump ( $ filter_table - > { output_chain $ bridge } ,
$ outputref ,
0 ,
match_dest_dev ( $ interface , 1 ) )
unless get_interface_option ( $ interface , 'port' ) ;
}
} else {
add_rule ( $ filter_table - > { FORWAR } , match_source_dev ( $ interface ) . match_dest_dev ( $ interface ) . '-j ACCEPT' ) unless $ interfaceref - > { nets } || ! $ interfaceref - > { options } { bridge } ;
2009-02-22 18:30:14 +01:00
2011-04-03 18:56:30 +02:00
add_jump ( $ filter_table - > { FORWARD } , $ forwardref , 0 , match_source_dev ( $ interface ) ) unless $ forward_jump_added { $ interface } || ! use_forward_chain $ interface , $ forwardref ;
add_jump ( $ filter_table - > { INPUT } , $ inputref , 0 , match_source_dev ( $ interface ) ) unless $ input_jump_added { $ interface } || ! use_input_chain $ interface , $ inputref ;
2010-03-11 02:25:06 +01:00
2011-04-03 18:56:30 +02:00
unless ( $ output_jump_added { $ interface } || ! use_output_chain $ interface , $ outputref ) {
add_jump $ filter_table - > { OUTPUT } , $ outputref , 0 , match_dest_dev ( $ interface ) unless get_interface_option ( $ interface , 'port' ) ;
}
2009-02-22 18:30:14 +01:00
}
}
2010-07-01 05:35:46 +02:00
handle_loopback_traffic ;
2009-02-22 18:30:14 +01:00
}
# Generate the rules matrix.
#
2009-10-20 21:24:28 +02:00
# Stealing a comment from the Burroughs B6700 MCP Operating System source, "generate_matrix makes a sow's ear out of a silk purse".
2009-02-22 18:30:14 +01:00
#
# The biggest disadvantage of the zone-policy-rule model used by Shorewall is that it doesn't scale well as the number of zones increases (Order N**2 where N = number of zones).
# A major goal of the rewrite of the compiler in Perl was to restrict those scaling effects to this function and the rules that it generates.
#
2010-12-29 02:18:43 +01:00
# The function traverses the full "source-zone by destination-zone" matrix and generates the rules necessary to direct traffic through the right set of filter-table and
# nat-table rules.
2009-02-22 18:30:14 +01:00
#
sub generate_matrix () {
my @ interfaces = ( all_interfaces ) ;
2010-12-18 05:16:09 +01:00
#
# Should this be the real PREROUTING chain?
#
2009-02-22 18:30:14 +01:00
my $ preroutingref = ensure_chain 'nat' , 'dnat' ;
2010-12-18 05:16:09 +01:00
my $ fw = firewall_zone ;
my @ zones = off_firewall_zones ;
my @ vservers = vserver_zones ;
2009-02-22 18:30:14 +01:00
my $ notrackref = $ raw_table - > { notrack_chain $ fw } ;
2011-05-26 22:38:44 +02:00
my $ state = $ config { BLACKLISTNEWONLY } ? $ globals { UNTRACKED } ? "$globals{STATEMATCH} NEW,INVALID,UNTRACKED " : "$globals{STATEMATCH} NEW,INVALID " : '' ;
2009-02-22 18:30:14 +01:00
my $ interface_jumps_added = 0 ;
2010-12-18 05:16:09 +01:00
2009-10-17 19:59:41 +02:00
our % input_jump_added = ( ) ;
our % output_jump_added = ( ) ;
our % forward_jump_added = ( ) ;
2011-04-03 18:56:30 +02:00
my % ipsec_jump_added = ( ) ;
2009-02-22 18:30:14 +01:00
2010-03-08 22:11:10 +01:00
progress_message2 'Generating Rule Matrix...' ;
2010-09-26 01:07:56 +02:00
progress_message ' Handling blacklisting and complex zones...' ;
2011-05-23 02:42:50 +02:00
2009-02-22 18:30:14 +01:00
#
2010-09-25 00:25:57 +02:00
# Special processing for complex and/or blacklisting configurations
2009-02-22 18:30:14 +01:00
#
for my $ zone ( @ zones ) {
2009-10-18 17:47:20 +02:00
my $ zoneref = find_zone ( $ zone ) ;
2010-09-25 00:25:57 +02:00
my $ simple = @ zones <= 2 && ! $ zoneref - > { options } { complex } ;
#
# Handle blacklisting first
#
2010-09-16 18:40:28 +02:00
if ( $ zoneref - > { options } { in } { blacklist } ) {
my $ blackref = $ filter_table - > { blacklst } ;
2011-02-21 00:35:58 +01:00
add_jump ensure_rules_chain ( rules_chain ( $ zone , $ _ ) ) , $ blackref , 0 , $ state , 0 , - 1 for firewall_zone , @ vservers ;
2010-09-27 20:16:18 +02:00
2010-09-25 00:25:57 +02:00
if ( $ simple ) {
2010-09-26 01:07:56 +02:00
#
# We won't create a zone forwarding chain for this zone so we must add blacklisting jumps to the rules chains
#
2010-09-25 00:25:57 +02:00
for my $ zone1 ( @ zones ) {
my $ ruleschain = rules_chain ( $ zone , $ zone1 ) ;
my $ ruleschainref = $ filter_table - > { $ ruleschain } ;
2010-09-27 20:16:18 +02:00
2010-09-26 01:07:56 +02:00
if ( ( $ zone ne $ zone1 || $ ruleschainref - > { referenced } ) && $ ruleschainref - > { policy } ne 'NONE' ) {
2011-02-21 00:35:58 +01:00
add_jump ( ensure_rules_chain ( $ ruleschain ) , $ blackref , 0 , $ state , 0 , - 1 ) ;
2010-09-25 00:25:57 +02:00
}
}
}
2010-09-16 18:40:28 +02:00
}
if ( $ zoneref - > { options } { out } { blacklist } ) {
my $ blackref = $ filter_table - > { blackout } ;
2011-02-21 00:35:58 +01:00
add_jump ensure_rules_chain ( rules_chain ( firewall_zone , $ zone ) ) , $ blackref , 0 , $ state , 0 , - 1 ;
2010-09-16 18:40:28 +02:00
2010-09-18 01:38:34 +02:00
for my $ zone1 ( @ zones , @ vservers ) {
2010-09-17 03:19:16 +02:00
my $ ruleschain = rules_chain ( $ zone1 , $ zone ) ;
my $ ruleschainref = $ filter_table - > { $ ruleschain } ;
2010-09-26 01:07:56 +02:00
if ( ( $ zone ne $ zone1 || $ ruleschainref - > { referenced } ) && $ ruleschainref - > { policy } ne 'NONE' ) {
2011-02-21 00:35:58 +01:00
add_jump ( ensure_rules_chain ( $ ruleschain ) , $ blackref , 0 , $ state , 0 , - 1 ) ;
2010-09-27 20:16:18 +02:00
}
2010-09-16 18:40:28 +02:00
}
}
2010-09-16 15:55:48 +02:00
2010-09-25 00:25:57 +02:00
next if $ simple ;
2010-09-27 20:16:18 +02:00
2010-09-24 20:16:31 +02:00
#
# Complex zone or we have more than one non-firewall zone -- create a zone forwarding chain
#
my $ frwd_ref = new_standard_chain zone_forward_chain ( $ zone ) ;
2010-09-24 21:04:06 +02:00
add_jump $ frwd_ref , $ filter_table - > { blacklst } , 0 , $ state , 0 , - 1 if $ zoneref - > { options } { in } { blacklist } ;
2010-09-24 20:16:31 +02:00
2010-01-25 17:13:22 +01:00
if ( have_ipsec ) {
2009-10-20 21:24:28 +02:00
#
# Because policy match only matches an 'in' or an 'out' policy (but not both), we have to place the
# '--pol ipsec --dir in' rules at the front of the (interface) forwarding chains. Otherwise, decrypted packets
# can match '--pol none --dir out' rules and send the packets down the wrong rules chain.
#
2009-02-22 18:30:14 +01:00
my $ type = $ zoneref - > { type } ;
my $ source_ref = ( $ zoneref - > { hosts } { ipsec } ) || { } ;
for my $ interface ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys %$ source_ref ) {
2010-03-11 02:25:06 +01:00
my $ sourcechainref = $ filter_table - > { forward_chain $ interface } ;
2009-02-22 18:30:14 +01:00
my $ interfacematch = '' ;
2011-04-03 18:56:30 +02:00
my $ interfaceref = find_interface $ interface ;
2009-02-22 18:30:14 +01:00
2010-03-11 02:25:06 +01:00
if ( use_forward_chain ( $ interface , $ sourcechainref ) ) {
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { ports } && $ interfaceref - > { options } { bridge } ) {
$ interfacematch = match_source_dev $ interface ;
copy_rules ( $ sourcechainref , $ frwd_ref , 1 ) unless $ ipsec_jump_added { $ zone } + + ;
$ sourcechainref = $ filter_table - > { FORWARD } ;
} elsif ( $ interfaceref - > { options } { port } ) {
add_jump ( $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ,
$ sourcechainref ,
0 ,
match_source_dev ( $ interface , 1 ) )
unless $ forward_jump_added { $ interface } + + ;
} else {
add_jump $ filter_table - > { FORWARD } , $ sourcechainref , 0 , match_source_dev ( $ interface ) unless $ forward_jump_added { $ interface } + + ;
}
2009-02-22 18:30:14 +01:00
} else {
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { options } { port } ) {
$ sourcechainref = $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ;
$ interfacematch = match_source_dev $ interface , 1 ;
} else {
$ sourcechainref = $ filter_table - > { FORWARD } ;
$ interfacematch = match_source_dev $ interface ;
}
2009-02-22 18:30:14 +01:00
move_rules ( $ filter_table - > { forward_chain $ interface } , $ frwd_ref ) ;
}
my $ arrayref = $ source_ref - > { $ interface } ;
for my $ hostref ( @ { $ arrayref } ) {
my $ ipsec_match = match_ipsec_in $ zone , $ hostref ;
for my $ net ( @ { $ hostref - > { hosts } } ) {
add_jump (
$ sourcechainref ,
2009-11-28 16:23:23 +01:00
source_exclusion ( $ hostref - > { exclusions } , $ frwd_ref ) ,
2009-08-26 21:44:10 +02:00
! @ { $ zoneref - > { parents } } ,
2009-02-22 18:30:14 +01:00
join ( '' , $ interfacematch , match_source_net ( $ net ) , $ ipsec_match )
) ;
}
}
}
}
}
#
# NOTRACK from firewall
#
2010-01-16 18:53:53 +01:00
add_jump $ raw_table - > { OUTPUT } , $ notrackref , 0 if $ notrackref - > { referenced } ;
2009-02-22 18:30:14 +01:00
#
# Main source-zone matrix-generation loop
#
2010-09-26 01:07:56 +02:00
progress_message ' Entering main matrix-generation loop...' ;
2009-02-22 18:30:14 +01:00
for my $ zone ( @ zones ) {
my $ zoneref = find_zone ( $ zone ) ;
my $ source_hosts_ref = $ zoneref - > { hosts } ;
my $ chain1 = rules_target firewall_zone , $ zone ;
my $ chain2 = rules_target $ zone , firewall_zone ;
my $ complex = $ zoneref - > { options } { complex } || 0 ;
my $ type = $ zoneref - > { type } ;
my $ frwd_ref = $ filter_table - > { zone_forward_chain $ zone } ;
my $ chain = 0 ;
my $ dnatref = ensure_chain 'nat' , dnat_chain ( $ zone ) ;
my $ notrackref = ensure_chain 'raw' , notrack_chain ( $ zone ) ;
my $ nested = $ zoneref - > { options } { nested } ;
my $ parenthasnat = 0 ;
my $ parenthasnotrack = 0 ;
if ( $ nested ) {
#
# This is a sub-zone. We need to determine if
#
# a) A parent zone defines DNAT/REDIRECT or notrack rules; and
# b) The current zone has a CONTINUE policy to some other zone.
#
# If a) but not b), then we must avoid sending packets from this
# zone through the DNAT/REDIRECT or notrack chain for the parent.
#
for my $ parent ( @ { $ zoneref - > { parents } } ) {
my $ ref1 = $ nat_table - > { dnat_chain $ parent } || { } ;
my $ ref2 = $ raw_table - > { notrack_chain $ parent } || { } ;
$ parenthasnat = 1 if $ ref1 - > { referenced } ;
$ parenthasnotrack = 1 if $ ref2 - > { referenced } ;
last if $ parenthasnat && $ parenthasnotrack ;
}
if ( $ parenthasnat || $ parenthasnotrack ) {
for my $ zone1 ( all_zones ) {
2009-11-14 16:07:19 +01:00
if ( $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } eq 'CONTINUE' ) {
2009-02-22 18:30:14 +01:00
#
# This zone has a continue policy to another zone. We must
# send packets from this zone through the parent's DNAT/REDIRECT/NOTRACK chain.
#
$ nested = 0 ;
last ;
}
}
} else {
#
# No parent has DNAT or notrack so there is nothing to worry about. Don't bother to generate needless RETURN rules in the 'dnat' or 'notrack' chain.
#
$ nested = 0 ;
}
}
#
# Take care of PREROUTING, INPUT and OUTPUT jumps
#
for my $ typeref ( values %$ source_hosts_ref ) {
for my $ interface ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys %$ typeref ) {
my $ arrayref = $ typeref - > { $ interface } ;
2011-04-03 18:56:30 +02:00
my $ interfaceref = find_interface $ interface ;
my $ isport = $ interfaceref - > { options } { port } ;
my $ bridge = $ interfaceref - > { bridge } ;
2009-02-22 18:30:14 +01:00
2010-07-31 19:49:49 +02:00
if ( get_physical ( $ interface ) eq '+' ) {
2009-02-22 18:30:14 +01:00
#
# Insert the interface-specific jumps before this one which is not interface-specific
#
add_interface_jumps ( @ interfaces ) unless $ interface_jumps_added + + ;
}
for my $ hostref ( @$ arrayref ) {
my $ ipsec_in_match = match_ipsec_in $ zone , $ hostref ;
my $ ipsec_out_match = match_ipsec_out $ zone , $ hostref ;
my $ exclusions = $ hostref - > { exclusions } ;
2010-09-27 20:16:18 +02:00
2009-02-22 18:30:14 +01:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
my $ dest = match_dest_net $ net ;
2010-04-16 18:56:11 +02:00
if ( $ chain1 && zone_type ( $ zone ) != BPORT ) {
2010-02-03 15:57:51 +01:00
my $ chain1ref = $ filter_table - > { $ chain1 } ;
2009-02-22 18:30:14 +01:00
my $ nextchain = dest_exclusion ( $ exclusions , $ chain1 ) ;
my $ outputref ;
2010-02-03 15:57:51 +01:00
my $ interfacechainref = $ filter_table - > { output_chain $ interface } ;
2009-02-22 18:30:14 +01:00
my $ interfacematch = '' ;
2010-02-03 04:42:54 +01:00
my $ use_output = 0 ;
2009-02-22 18:30:14 +01:00
2010-09-15 16:38:20 +02:00
if ( @ vservers || use_output_chain ( $ interface , $ interfacechainref ) || ( @ { $ interfacechainref - > { rules } } && ! $ chain1ref ) ) {
2010-02-03 15:57:51 +01:00
$ outputref = $ interfacechainref ;
2011-04-03 18:56:30 +02:00
if ( $ isport ) {
add_jump ( $ filter_table - > { output_chain $ bridge } ,
$ outputref ,
0 ,
match_dest_dev ( $ interface , 1 ) )
unless $ output_jump_added { $ interface } + + ;
} else {
add_jump $ filter_table - > { OUTPUT } , $ outputref , 0 , match_dest_dev ( $ interface ) unless $ output_jump_added { $ interface } + + ;
}
2010-02-03 04:42:54 +01:00
$ use_output = 1 ;
2010-07-01 05:35:46 +02:00
2010-07-16 19:06:29 +02:00
unless ( lc $ net eq IPv6_LINKLOCAL ) {
2010-07-12 21:39:51 +02:00
for my $ vzone ( vserver_zones ) {
generate_source_rules ( $ outputref , $ vzone , $ zone , $ dest ) ;
}
}
2011-04-03 18:56:30 +02:00
} elsif ( $ isport ) {
$ outputref = $ filter_table - > { output_chain $ bridge } ;
$ interfacematch = match_dest_dev $ interface , 1 ;
2009-02-22 18:30:14 +01:00
} else {
$ outputref = $ filter_table - > { OUTPUT } ;
$ interfacematch = match_dest_dev $ interface ;
}
add_jump $ outputref , $ nextchain , 0 , join ( '' , $ interfacematch , $ dest , $ ipsec_out_match ) ;
add_jump ( $ outputref , $ nextchain , 0 , join ( '' , $ interfacematch , '-d 255.255.255.255 ' , $ ipsec_out_match ) )
2010-07-12 04:52:18 +02:00
if $ family == F_IPV4 && $ hostref - > { options } { broadcast } ;
2009-02-22 18:30:14 +01:00
2010-02-03 15:57:51 +01:00
move_rules ( $ interfacechainref , $ chain1ref ) unless $ use_output ;
2009-02-22 18:30:14 +01:00
}
clearrule ;
2009-08-20 23:32:15 +02:00
next if $ hostref - > { options } { destonly } ;
2009-02-22 18:30:14 +01:00
my $ source = match_source_net $ net ;
if ( $ dnatref - > { referenced } ) {
#
# There are DNAT/REDIRECT rules with this zone as the source.
# Add a jump from this source network to this zone's DNAT/REDIRECT chain
#
2011-04-07 00:14:39 +02:00
add_jump ( $ preroutingref ,
source_exclusion ( $ exclusions , $ dnatref ) ,
0 ,
join ( '' , match_source_dev ( $ interface ) , $ source , $ ipsec_in_match ) ) ;
if ( get_physical ( $ interface ) eq '+' ) {
#
2011-04-08 16:50:54 +02:00
# The jump from the PREROUTING chain to dnat may not have been added above
2011-04-07 00:14:39 +02:00
#
addnatjump 'PREROUTING' , 'dnat' , '' unless $ preroutingref - > { references } { PREROUTING } ;
}
2010-02-01 23:24:07 +01:00
check_optimization ( $ dnatref ) if $ source ;
2009-02-22 18:30:14 +01:00
}
if ( $ notrackref - > { referenced } ) {
#
# There are notrack rules with this zone as the source.
# Add a jump from this source network to this zone's notrack chain
#
add_jump $ raw_table - > { PREROUTING } , source_exclusion ( $ exclusions , $ notrackref ) , 0 , join ( '' , match_source_dev ( $ interface ) , $ source , $ ipsec_in_match ) ;
}
2010-02-01 23:24:07 +01:00
2009-02-22 18:30:14 +01:00
#
# If this zone has parents with DNAT/REDIRECT or notrack rules and there are no CONTINUE polcies with this zone as the source
# then add a RETURN jump for this source network.
#
if ( $ nested ) {
add_rule $ preroutingref , join ( '' , match_source_dev ( $ interface ) , $ source , $ ipsec_in_match , '-j RETURN' ) if $ parenthasnat ;
add_rule $ raw_table - > { PREROUTING } , join ( '' , match_source_dev ( $ interface ) , $ source , $ ipsec_in_match , '-j RETURN' ) if $ parenthasnotrack ;
}
2010-02-03 15:57:51 +01:00
my $ chain2ref = $ filter_table - > { $ chain2 } ;
2009-02-22 18:30:14 +01:00
my $ inputchainref ;
2010-02-03 15:57:51 +01:00
my $ interfacechainref = $ filter_table - > { input_chain $ interface } ;
2009-02-22 18:30:14 +01:00
my $ interfacematch = '' ;
2010-02-03 04:42:54 +01:00
my $ use_input ;
2010-09-16 18:40:28 +02:00
my $ blacklist = $ zoneref - > { options } { in } { blacklist } ;
2009-02-22 18:30:14 +01:00
2010-07-01 05:35:46 +02:00
if ( @ vservers || use_input_chain ( $ interface , $ interfacechainref ) || ! $ chain2 || ( @ { $ interfacechainref - > { rules } } && ! $ chain2ref ) ) {
2010-02-03 15:57:51 +01:00
$ inputchainref = $ interfacechainref ;
2011-04-03 18:56:30 +02:00
if ( $ isport ) {
add_jump ( $ filter_table - > { input_chain $ bridge } ,
$ inputchainref ,
0 ,
match_source_dev ( $ interface , 1 ) )
unless $ input_jump_added { $ interface } + + ;
} else {
add_jump $ filter_table - > { INPUT } , $ inputchainref , 0 , match_source_dev ( $ interface ) unless $ input_jump_added { $ interface } + + ;
}
2010-02-03 04:42:54 +01:00
$ use_input = 1 ;
2010-07-01 05:35:46 +02:00
2010-07-16 19:06:29 +02:00
unless ( lc $ net eq IPv6_LINKLOCAL ) {
2010-07-12 20:52:56 +02:00
for my $ vzone ( @ vservers ) {
my $ target = rules_target ( $ zone , $ vzone ) ;
generate_dest_rules ( $ inputchainref , $ target , $ vzone , $ source . $ ipsec_in_match ) if $ target ;
}
2010-07-01 05:35:46 +02:00
}
2011-04-03 18:56:30 +02:00
} elsif ( $ isport ) {
$ inputchainref = $ filter_table - > { input_chain $ bridge } ;
$ interfacematch = match_source_dev $ interface , 1 ;
2009-02-22 18:30:14 +01:00
} else {
$ inputchainref = $ filter_table - > { INPUT } ;
$ interfacematch = match_source_dev $ interface ;
}
if ( $ chain2 ) {
add_jump $ inputchainref , source_exclusion ( $ exclusions , $ chain2 ) , 0 , join ( '' , $ interfacematch , $ source , $ ipsec_in_match ) ;
2010-02-03 15:57:51 +01:00
move_rules ( $ interfacechainref , $ chain2ref ) unless $ use_input ;
2009-02-22 18:30:14 +01:00
}
if ( $ frwd_ref && $ hostref - > { ipsec } ne 'ipsec' ) {
my $ ref = source_exclusion ( $ exclusions , $ frwd_ref ) ;
2010-03-11 02:25:06 +01:00
my $ forwardref = $ filter_table - > { forward_chain $ interface } ;
2011-04-03 18:56:30 +02:00
2010-03-11 02:25:06 +01:00
if ( use_forward_chain $ interface , $ forwardref ) {
2009-10-17 19:59:41 +02:00
add_jump $ forwardref , $ ref , 0 , join ( '' , $ source , $ ipsec_in_match ) ;
2011-04-03 18:56:30 +02:00
if ( $ isport ) {
add_jump ( $ filter_table - > { forward_chain $ bridge } ,
$ forwardref ,
0 ,
match_source_dev ( $ interface , 1 ) )
unless $ forward_jump_added { $ interface } + + ;
} else {
add_jump $ filter_table - > { FORWARD } , $ forwardref , 0 , match_source_dev ( $ interface ) unless $ forward_jump_added { $ interface } + + ;
}
2009-02-22 18:30:14 +01:00
} else {
2011-04-03 18:56:30 +02:00
if ( $ isport ) {
add_jump ( $ filter_table - > { forward_chain $ bridge } ,
$ ref ,
0 ,
join ( '' , match_source_dev ( $ interface , 1 ) , $ source , $ ipsec_in_match ) ) ;
} else {
add_jump $ filter_table - > { FORWARD } , $ ref , 0 , join ( '' , match_source_dev ( $ interface ) , $ source , $ ipsec_in_match ) ;
}
2010-03-11 02:25:06 +01:00
move_rules ( $ forwardref , $ frwd_ref ) ;
2009-02-22 18:30:14 +01:00
}
}
}
}
}
}
#
# F O R W A R D I N G
#
my @ dest_zones ;
my $ last_chain = '' ;
2010-01-16 18:53:53 +01:00
if ( $ config { OPTIMIZE } & 1 ) {
2009-02-22 18:30:14 +01:00
my @ temp_zones ;
for my $ zone1 ( @ zones ) {
my $ zone1ref = find_zone ( $ zone1 ) ;
2009-11-14 16:07:19 +01:00
my $ policy = $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } ;
2009-02-22 18:30:14 +01:00
2009-11-03 18:28:34 +01:00
next if $ policy eq 'NONE' ;
2009-02-22 18:30:14 +01:00
my $ chain = rules_target $ zone , $ zone1 ;
next unless $ chain ;
if ( $ zone eq $ zone1 ) {
next if ( scalar ( keys ( % { $ zoneref - > { interfaces } } ) ) < 2 ) && ! $ zoneref - > { options } { in_out } { routeback } ;
}
2009-03-13 23:59:49 +01:00
if ( $ zone1ref - > { type } == BPORT ) {
2009-02-22 18:30:14 +01:00
next unless $ zoneref - > { bridge } eq $ zone1ref - > { bridge } ;
}
2009-11-12 21:30:08 +01:00
if ( $ chain =~ /(2all|-all)$/ ) {
2009-02-22 18:30:14 +01:00
if ( $ chain ne $ last_chain ) {
$ last_chain = $ chain ;
push @ dest_zones , @ temp_zones ;
@ temp_zones = ( $ zone1 ) ;
} elsif ( $ policy eq 'ACCEPT' ) {
push @ temp_zones , $ zone1 ;
} else {
$ last_chain = $ chain ;
@ temp_zones = ( $ zone1 ) ;
}
} else {
push @ dest_zones , @ temp_zones , $ zone1 ;
@ temp_zones = ( ) ;
$ last_chain = '' ;
}
}
if ( $ last_chain && @ temp_zones == 1 ) {
push @ dest_zones , @ temp_zones ;
$ last_chain = '' ;
}
} else {
@ dest_zones = @ zones ;
}
#
# Here it is -- THE BIG UGLY!!!!!!!!!!!!
#
# We now loop through the destination zones creating jumps to the rules chain for each source/dest combination.
# @dest_zones is the list of destination zones that we need to handle from this source zone
#
for my $ zone1 ( @ dest_zones ) {
my $ zone1ref = find_zone ( $ zone1 ) ;
2009-11-14 16:07:19 +01:00
next if $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } eq 'NONE' ;
2009-02-22 18:30:14 +01:00
my $ chain = rules_target $ zone , $ zone1 ;
next unless $ chain ; # CONTINUE policy with no rules
my $ num_ifaces = 0 ;
if ( $ zone eq $ zone1 ) {
2009-10-18 17:47:20 +02:00
next if ( $ num_ifaces = scalar ( keys ( % { $ zoneref - > { interfaces } } ) ) ) < 2 && ! $ zoneref - > { options } { in_out } { routeback } ;
2009-02-22 18:30:14 +01:00
}
2009-03-13 23:59:49 +01:00
if ( $ zone1ref - > { type } == BPORT ) {
2009-10-18 17:47:20 +02:00
next unless $ zoneref - > { bridge } eq $ zone1ref - > { bridge } ;
2009-02-22 18:30:14 +01:00
}
2009-11-03 18:28:34 +01:00
my $ chainref = $ filter_table - > { $ chain } ; #Will be null if $chain is a Netfilter Built-in target like ACCEPT
2009-02-22 18:30:14 +01:00
if ( $ frwd_ref ) {
2009-11-03 18:28:34 +01:00
#
# Simple case -- the source zone has it's own forwarding chain
#
for my $ typeref ( values % { $ zone1ref - > { hosts } } ) {
2009-02-22 18:30:14 +01:00
for my $ interface ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys %$ typeref ) {
2009-11-03 18:28:34 +01:00
for my $ hostref ( @ { $ typeref - > { $ interface } } ) {
2009-02-22 18:30:14 +01:00
next if $ hostref - > { options } { sourceonly } ;
if ( $ zone ne $ zone1 || $ num_ifaces > 1 || $ hostref - > { options } { routeback } ) {
my $ ipsec_out_match = match_ipsec_out $ zone1 , $ hostref ;
2009-11-28 16:25:31 +01:00
my $ dest_exclusion = dest_exclusion ( $ hostref - > { exclusions } , $ chain ) ;
2009-02-22 18:30:14 +01:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
2009-11-28 16:25:31 +01:00
add_jump $ frwd_ref , $ dest_exclusion , 0 , join ( '' , match_dest_dev ( $ interface ) , match_dest_net ( $ net ) , $ ipsec_out_match ) ;
2009-02-22 18:30:14 +01:00
}
}
}
}
}
} else {
2009-11-03 18:28:34 +01:00
#
# More compilcated case. If the interface is associated with a single simple zone, we try to combine the interface's forwarding chain with the rules chain
#
2009-02-22 18:30:14 +01:00
for my $ typeref ( values %$ source_hosts_ref ) {
for my $ interface ( keys %$ typeref ) {
2011-04-03 18:56:30 +02:00
my $ interfaceref = find_interface $ interface ;
2009-02-22 18:30:14 +01:00
my $ chain3ref ;
my $ match_source_dev = '' ;
2009-11-02 16:15:20 +01:00
my $ forwardchainref = $ filter_table - > { forward_chain $ interface } ;
2009-02-22 18:30:14 +01:00
2010-03-11 02:25:06 +01:00
if ( use_forward_chain ( $ interface , $ forwardchainref ) || ( @ { $ forwardchainref - > { rules } } && ! $ chainref ) ) {
2009-11-02 16:15:20 +01:00
#
# Either we must use the interface's forwarding chain or that chain has rules and we have nowhere to move them
#
$ chain3ref = $ forwardchainref ;
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { options } { port } ) {
add_jump ( $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ,
$ chain3ref ,
0 ,
match_source_dev ( $ interface , 1 ) )
unless $ forward_jump_added { $ interface } + + ;
} else {
add_jump $ filter_table - > { FORWARD } , $ chain3ref , 0 , match_source_dev ( $ interface ) unless $ forward_jump_added { $ interface } + + ;
}
2009-02-22 18:30:14 +01:00
} else {
2009-11-03 18:28:34 +01:00
#
# Don't use the interface's forward chain -- move any rules in that chain to this rules chain
#
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { options } { port } ) {
$ chain3ref = $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ;
$ match_source_dev = match_source_dev $ interface , 1 ;
} else {
$ chain3ref = $ filter_table - > { FORWARD } ;
$ match_source_dev = match_source_dev $ interface ;
}
2009-11-03 00:35:00 +01:00
move_rules $ forwardchainref , $ chainref ;
2009-02-22 18:30:14 +01:00
}
2009-11-03 18:28:34 +01:00
for my $ hostref ( @ { $ typeref - > { $ interface } } ) {
2009-02-22 18:30:14 +01:00
next if $ hostref - > { options } { destonly } ;
my $ excl3ref = source_exclusion ( $ hostref - > { exclusions } , $ chain3ref ) ;
for my $ net ( @ { $ hostref - > { hosts } } ) {
2009-11-03 18:28:34 +01:00
for my $ type1ref ( values % { $ zone1ref - > { hosts } } ) {
2009-02-22 18:30:14 +01:00
for my $ interface1 ( keys %$ type1ref ) {
my $ array1ref = $ type1ref - > { $ interface1 } ;
for my $ host1ref ( @$ array1ref ) {
next if $ host1ref - > { options } { sourceonly } ;
my $ ipsec_out_match = match_ipsec_out $ zone1 , $ host1ref ;
2009-11-28 16:25:31 +01:00
my $ dest_exclusion = dest_exclusion ( $ host1ref - > { exclusions } , $ chain ) ;
2009-02-22 18:30:14 +01:00
for my $ net1 ( @ { $ host1ref - > { hosts } } ) {
unless ( $ interface eq $ interface1 && $ net eq $ net1 && ! $ host1ref - > { options } { routeback } ) {
#
# We defer evaluation of the source net match to accomodate systems without $capabilities{KLUDEFREE};
#
add_jump (
$ excl3ref ,
2009-11-28 16:25:31 +01:00
$ dest_exclusion ,
2009-02-22 18:30:14 +01:00
0 ,
2009-08-20 23:32:15 +02:00
join ( '' ,
$ match_source_dev ,
match_dest_dev ( $ interface1 ) ,
match_source_net ( $ net ) ,
match_dest_net ( $ net1 ) ,
2009-02-22 18:30:14 +01:00
$ ipsec_out_match )
2009-11-28 16:20:28 +01:00
) ;
2009-02-22 18:30:14 +01:00
}
}
}
}
}
}
}
}
}
}
}
2009-11-03 18:28:34 +01:00
#
# E N D F O R W A R D I N G
#
# Now add an unconditional jump to the last unique policy-only chain determined above, if any
#
add_jump $ frwd_ref , $ last_chain , 1 if $ frwd_ref && $ last_chain ;
2009-02-22 18:30:14 +01:00
}
2010-09-26 01:07:56 +02:00
progress_message ' Finishing matrix...' ;
2009-02-22 18:30:14 +01:00
add_interface_jumps @ interfaces unless $ interface_jumps_added ;
2010-09-18 17:36:59 +02:00
promote_blacklist_rules ;
2009-02-22 18:30:14 +01:00
my % builtins = ( mangle = > [ qw/PREROUTING INPUT FORWARD POSTROUTING/ ] ,
nat = > [ qw/PREROUTING OUTPUT POSTROUTING/ ] ,
filter = > [ qw/INPUT FORWARD OUTPUT/ ] ) ;
2010-08-01 17:36:56 +02:00
unless ( $ config { COMPLETE } ) {
complete_standard_chain $ filter_table - > { INPUT } , 'all' , firewall_zone , 'DROP' ;
complete_standard_chain $ filter_table - > { OUTPUT } , firewall_zone , 'all' , 'REJECT' ;
complete_standard_chain $ filter_table - > { FORWARD } , 'all' , 'all' , 'REJECT' ;
}
2009-02-22 18:30:14 +01:00
if ( $ config { LOGALLNEW } ) {
for my $ table qw/mangle nat filter/ {
for my $ chain ( @ { $ builtins { $ table } } ) {
log_rule_limit
$ config { LOGALLNEW } ,
$ chain_table { $ table } { $ chain } ,
$ table ,
$ chain ,
'' ,
'' ,
'insert' ,
2010-04-25 22:35:41 +02:00
"$globals{STATEMATCH} NEW " ;
2009-02-22 18:30:14 +01:00
}
}
}
}
sub setup_mss ( ) {
my $ clampmss = $ config { CLAMPMSS } ;
my $ option ;
my $ match = '' ;
my $ chainref = $ filter_table - > { FORWARD } ;
if ( $ clampmss ) {
if ( "\L$clampmss" eq 'yes' ) {
$ option = '--clamp-mss-to-pmtu' ;
} else {
2010-01-25 16:56:16 +01:00
$ match = "-m tcpmss --mss $clampmss: " if have_capability ( 'TCPMSS_MATCH' ) ;
2009-02-22 18:30:14 +01:00
$ option = "--set-mss $clampmss" ;
}
2010-01-25 17:13:22 +01:00
$ match . = '-m policy --pol none --dir out ' if have_ipsec ;
2009-02-22 18:30:14 +01:00
}
my $ interfaces = find_interfaces_by_option ( 'mss' ) ;
if ( @$ interfaces ) {
#
# Since we will need multiple rules, we create a separate chain
#
$ chainref = new_chain 'filter' , 'settcpmss' ;
#
# Send all forwarded SYN packets to the 'settcpmss' chain
#
2010-01-16 18:53:53 +01:00
add_jump $ filter_table - > { FORWARD } , $ chainref , 0 , '-p tcp --tcp-flags SYN,RST SYN ' ;
2009-02-22 18:30:14 +01:00
my $ in_match = '' ;
my $ out_match = '' ;
2010-01-25 17:13:22 +01:00
if ( have_ipsec ) {
2009-02-22 18:30:14 +01:00
$ in_match = '-m policy --pol none --dir in ' ;
$ out_match = '-m policy --pol none --dir out ' ;
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
for ( @$ interfaces ) {
my $ mss = get_interface_option ( $ _ , 'mss' ) ;
2010-01-25 16:56:16 +01:00
my $ mssmatch = have_capability ( 'TCPMSS_MATCH' ) ? "-m tcpmss --mss $mss: " : '' ;
2009-11-05 20:44:40 +01:00
my $ source = match_source_dev $ _ ;
my $ dest = match_dest_dev $ _ ;
2009-11-05 22:40:03 +01:00
add_rule $ chainref , "${dest}-p tcp --tcp-flags SYN,RST SYN ${mssmatch}${out_match}-j TCPMSS --set-mss $mss" ;
add_rule $ chainref , "${dest}-j RETURN" if $ clampmss ;
add_rule $ chainref , "${source}-p tcp --tcp-flags SYN,RST SYN ${mssmatch}${in_match}-j TCPMSS --set-mss $mss" ;
add_rule $ chainref , "${source}-j RETURN" if $ clampmss ;
2009-02-22 18:30:14 +01:00
}
}
add_rule $ chainref , "-p tcp --tcp-flags SYN,RST SYN ${match}-j TCPMSS $option" if $ clampmss ;
}
2009-03-28 20:22:15 +01:00
#
# Compile the stop_firewall() function
#
2010-01-16 18:53:53 +01:00
sub compile_stop_firewall ( $$ ) {
my ( $ test , $ export ) = @ _ ;
2009-03-28 20:22:15 +01:00
2009-04-01 00:42:37 +02:00
my $ input = $ filter_table - > { INPUT } ;
my $ output = $ filter_table - > { OUTPUT } ;
my $ forward = $ filter_table - > { FORWARD } ;
2009-03-28 20:22:15 +01:00
emit << 'EOF' ;
#
# Stop/restore the firewall after an error or because of a 'stop' or 'clear' command
#
stop_firewall ( ) {
2010-01-04 19:14:36 +01:00
local hack
2009-03-28 20:22:15 +01:00
EOF
2009-04-01 00:42:37 +02:00
$ output - > { policy } = 'ACCEPT' if $ config { ADMINISABSENTMINDED } ;
2009-03-30 02:49:00 +02:00
2009-03-28 20:22:15 +01:00
if ( $ family == F_IPV4 ) {
2010-09-17 03:19:16 +02:00
emit << 'EOF' ;
deletechain ( ) {
qt $ IPTABLES - L $ 1 - n && qt $ IPTABLES - F $ 1 && qt $ IPTABLES - X $ 1
2009-03-28 20:22:15 +01:00
}
case $ COMMAND in
2010-09-17 03:19:16 +02:00
stop | clear | restore )
2010-09-16 21:17:04 +02:00
if chain_exists dynamic ; then
2010-09-17 03:19:16 +02:00
$ { IPTABLES } - save - t filter | grep '^-A dynamic' > $ { VARDIR } / . dynamic
fi
; ;
* )
set + x
2010-09-16 21:17:04 +02:00
EOF
} else {
2010-09-17 03:19:16 +02:00
emit << 'EOF' ;
deletechain ( ) {
qt $ IPTABLES - L $ 1 - n && qt $ IPTABLES - F $ 1 && qt $ IPTABLES - X $ 1
2010-09-16 21:17:04 +02:00
}
2010-09-17 03:19:16 +02:00
case $ COMMAND in
stop | clear | restore )
if chain_exists dynamic ; then
$ { IP6TABLES } - save - t filter | grep '^-A dynamic' > $ { VARDIR } / . dynamic
2010-09-16 21:17:04 +02:00
fi
2010-09-17 03:19:16 +02:00
; ;
* )
set + x
EOF
}
2009-03-28 20:22:15 +01:00
2010-09-17 03:19:16 +02:00
emit << 'EOF' ;
2009-03-28 20:22:15 +01:00
case $ COMMAND in
start )
2010-03-02 21:34:36 +01:00
logger - p kern . err "ERROR:$g_product start failed"
2009-03-28 20:22:15 +01:00
; ;
restart )
2010-03-02 21:34:36 +01:00
logger - p kern . err "ERROR:$g_product restart failed"
2009-03-28 20:22:15 +01:00
; ;
2010-01-06 17:01:06 +01:00
refresh )
2010-03-02 21:34:36 +01:00
logger - p kern . err "ERROR:$g_product refresh failed"
2009-03-28 20:22:15 +01:00
; ;
esac
if [ "$RESTOREFILE" = NONE ] ; then
COMMAND = clear
clear_firewall
2010-03-02 21:34:36 +01:00
echo "$g_product Cleared"
2009-03-28 20:22:15 +01:00
kill $$
exit 2
else
2010-02-26 17:35:50 +01:00
g_restorepath = $ { VARDIR } / $ RESTOREFILE
2009-03-28 20:22:15 +01:00
2010-02-26 17:35:50 +01:00
if [ - x $ g_restorepath ] ; then
2010-03-02 21:34:36 +01:00
echo Restoring $ { g_product: = Shorewall } ...
2010-06-07 16:30:56 +02:00
2010-03-03 18:50:07 +01:00
g_recovering = Yes
2009-03-28 20:22:15 +01:00
2010-03-03 17:59:58 +01:00
if run_it $ g_restorepath restore ; then
2010-03-02 21:34:36 +01:00
echo "$g_product restored from $g_restorepath"
2010-03-17 18:10:56 +01:00
set_state "Restored from $g_restorepath"
2009-03-28 20:22:15 +01:00
else
set_state "Unknown"
fi
kill $$
exit 2
fi
fi
; ;
esac
2010-03-02 16:37:30 +01:00
if [ - n "$g_stopping" ] ; then
kill $$
exit 1
fi
2009-03-28 20:22:15 +01:00
2010-03-02 16:37:30 +01:00
set_state "Stopping"
2009-03-28 20:22:15 +01:00
2010-03-02 16:37:30 +01:00
g_stopping = "Yes"
2009-03-28 20:22:15 +01:00
deletechain shorewall
run_stop_exit
EOF
2010-01-25 16:56:16 +01:00
if ( have_capability ( 'NAT_ENABLED' ) ) {
2009-03-30 02:49:00 +02:00
emit << 'EOF' ;
if [ - f $ { VARDIR } / nat ] ; then
while read external interface ; do
del_ip_addr $ external $ interface
done < $ { VARDIR } / nat
rm - f $ { VARDIR } / nat
fi
2009-03-28 20:22:15 +01:00
EOF
}
if ( $ family == F_IPV4 ) {
emit << 'EOF' ;
if [ - f $ { VARDIR } / proxyarp ] ; then
while read address interface external haveroute ; do
2010-12-11 04:06:44 +01:00
qt $ IP - 4 neigh del proxy $ address dev $ external
[ - z "${haveroute}${g_noroutes}" ] && qt $ IP - 4 route del $ address / 32 dev $ interface
2009-03-28 20:22:15 +01:00
f = /proc/s ys /net/i pv4 /conf/ $ interface / proxy_arp
[ - f $ f ] && echo 0 > $ f
done < $ { VARDIR } / proxyarp
2009-03-30 02:49:00 +02:00
2010-12-11 16:10:50 +01:00
rm - f $ { VARDIR } / proxyarp
2009-03-28 20:22:15 +01:00
fi
EOF
2010-12-11 04:06:44 +01:00
} else {
emit << 'EOF' ;
if [ - f $ { VARDIR } / proxyndp ] ; then
while read address interface external haveroute ; do
qt $ IP - 6 neigh del proxy $ address dev $ external
[ - z "${haveroute}${g_noroutes}" ] && qt $ IP - 6 route del $ address / 128 dev $ interface
f = /proc/s ys /net/i pv4 /conf/ $ interface / proxy_ndp
[ - f $ f ] && echo 0 > $ f
done < $ { VARDIR } / proxyndp
2010-12-11 16:10:50 +01:00
rm - f $ { VARDIR } / proxyndp
2010-12-11 04:06:44 +01:00
fi
2010-12-11 16:10:50 +01:00
EOF
}
2009-03-28 20:22:15 +01:00
push_indent ;
emit 'delete_tc1' if $ config { CLEAR_TC } ;
emit ( 'undo_routing' ,
2011-04-14 21:17:46 +02:00
"restore_default_route $config{USE_DEFAULT_RT}"
2009-03-28 20:22:15 +01:00
) ;
2009-03-30 02:49:00 +02:00
my @ chains = $ config { ADMINISABSENTMINDED } ? qw/INPUT FORWARD/ : qw/INPUT OUTPUT FORWARD/ ;
2009-08-20 23:32:15 +02:00
2010-04-25 22:35:41 +02:00
add_rule $ filter_table - > { $ _ } , "$globals{STATEMATCH} ESTABLISHED,RELATED -j ACCEPT" for @ chains ;
2009-03-28 20:22:15 +01:00
if ( $ family == F_IPV6 ) {
2010-07-16 19:06:29 +02:00
add_rule $ input , '-s ' . IPv6_LINKLOCAL . ' -j ACCEPT' ;
add_rule $ input , '-d ' . IPv6_LINKLOCAL . ' -j ACCEPT' ;
add_rule $ input , '-d ' . IPv6_MULTICAST . ' -j ACCEPT' ;
2009-03-28 20:22:15 +01:00
2009-03-30 02:49:00 +02:00
unless ( $ config { ADMINISABSENTMINDED } ) {
2010-07-16 19:06:29 +02:00
add_rule $ output , '-d ' . IPv6_LINKLOCAL . ' -j ACCEPT' ;
add_rule $ output , '-d ' . IPv6_MULTICAST . ' -j ACCEPT' ;
2009-03-30 02:49:00 +02:00
}
2009-03-28 20:22:15 +01:00
}
process_routestopped ;
2009-04-01 00:42:37 +02:00
add_rule $ input , '-i lo -j ACCEPT' ;
2009-03-28 20:22:15 +01:00
2009-04-01 00:42:37 +02:00
add_rule $ output , '-o lo -j ACCEPT' unless $ config { ADMINISABSENTMINDED } ;
2009-03-28 20:22:15 +01:00
my $ interfaces = find_interfaces_by_option 'dhcp' ;
if ( @$ interfaces ) {
my $ ports = $ family == F_IPV4 ? '67:68' : '546:547' ;
for my $ interface ( @$ interfaces ) {
2009-11-06 22:10:19 +01:00
add_rule $ input , "-p udp " . match_source_dev ( $ interface ) . "--dport $ports -j ACCEPT" ;
add_rule $ output , "-p udp " . match_dest_dev ( $ interface ) . "--dport $ports -j ACCEPT" unless $ config { ADMINISABSENTMINDED } ;
2009-03-28 20:22:15 +01:00
#
# This might be a bridge
#
2009-11-06 22:10:19 +01:00
add_rule $ forward , "-p udp " . match_source_dev ( $ interface ) . match_dest_dev ( $ interface ) . "--dport $ports -j ACCEPT" ;
2009-03-28 20:22:15 +01:00
}
}
emit '' ;
2009-03-30 02:49:00 +02:00
create_stop_load $ test ;
2009-03-28 20:22:15 +01:00
if ( $ family == F_IPV4 ) {
if ( $ config { IP_FORWARDING } eq 'on' ) {
emit ( 'echo 1 > /proc/sys/net/ipv4/ip_forward' ,
'progress_message2 IPv4 Forwarding Enabled' ) ;
} elsif ( $ config { IP_FORWARDING } eq 'off' ) {
emit ( 'echo 0 > /proc/sys/net/ipv4/ip_forward' ,
'progress_message2 IPv4 Forwarding Disabled!'
) ;
}
} else {
for my $ interface ( all_bridges ) {
2009-11-22 17:20:07 +01:00
emit "do_iptables -A FORWARD -p 58 " . match_source_dev ( $ interface ) . match_dest_dev ( $ interface ) . "-j ACCEPT" ;
2009-08-20 23:32:15 +02:00
}
2009-03-28 20:22:15 +01:00
if ( $ config { IP_FORWARDING } eq 'on' ) {
emit ( 'echo 1 > /proc/sys/net/ipv6/conf/all/forwarding' ,
'progress_message2 IPv6 Forwarding Enabled' ) ;
} elsif ( $ config { IP_FORWARDING } eq 'off' ) {
emit ( 'echo 0 > /proc/sys/net/ipv6/conf/all/forwarding' ,
'progress_message2 IPv6 Forwarding Disabled!'
) ;
}
}
pop_indent ;
emit '
run_stopped_exit ' ;
2009-08-20 23:32:15 +02:00
my @ ipsets = all_ipsets ;
2009-03-28 20:22:15 +01:00
2010-10-30 19:35:52 +02:00
if ( @ ipsets || ( $ config { SAVE_IPSETS } && have_ipset_rules ) ) {
2009-03-30 02:49:00 +02:00
emit << 'EOF' ;
2009-03-28 20:22:15 +01:00
2010-01-04 19:14:36 +01:00
case $ IPSET in
* / * )
if [ ! - x "$IPSET" ] ; then
error_message "ERROR: IPSET=$IPSET does not exist or is not executable - ipsets are not saved"
IPSET =
fi
; ;
* )
IPSET = "$(mywhich $IPSET)"
[ - n "$IPSET" ] || error_message "ERROR: The ipset utility cannot be located - ipsets are not saved"
; ;
esac
if [ - n "$IPSET" ] ; then
if [ - f /etc/ debian_version ] && [ $ ( cat /etc/ debian_version ) = 5.0 .3 ] ; then
#
# The 'grep -v' is a hack for a bug in ipset's nethash implementation when xtables-addons is applied to Lenny
#
hack = '| grep -v /31'
else
hack =
fi
if eval $ IPSET - S $ hack > $ { VARDIR } / ipsets . tmp ; then
2009-03-28 20:22:15 +01:00
#
# Don't save an 'empty' file
#
grep - q '^-N' $ { VARDIR } /ipsets.tmp && mv -f ${VARDIR}/i psets . tmp $ { VARDIR } / ipsets . save
2010-01-04 19:14:36 +01:00
fi
2009-03-30 20:00:23 +02:00
fi
2009-03-28 20:22:15 +01:00
EOF
}
2009-08-20 23:32:15 +02:00
emit '
2009-03-28 20:22:15 +01:00
2010-05-17 00:31:41 +02:00
set_state "Stopped"
logger - p kern . info "$g_product Stopped"
2009-03-28 20:22:15 +01:00
case $ COMMAND in
stop | clear )
; ;
* )
#
# The firewall is being stopped when we were trying to do something
# else. Kill the shell in case we\'re running in a subshell
#
kill $$
; ;
esac
}
' ;
}
2009-02-22 18:30:14 +01:00
1 ;