2009-02-22 18:30:14 +01:00
#
2016-01-28 22:46:34 +01:00
# Shorewall 5.0 -- /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]
#
2016-01-28 22:46:34 +01:00
# (c) 2007-2016 - Tom Eastep (teastep@shorewall.net)
2009-02-22 18:30:14 +01:00
#
# Complete documentation is available at http://shorewall.net
#
2014-01-04 18:48:27 +01:00
# This program is part of Shorewall.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 2 of the license or, at your
# option, any later version.
#
# 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, see <http://www.gnu.org/licenses/>.
2009-02-22 18:30:14 +01:00
#
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
2015-08-07 22:46:16 +02:00
convert_routestopped
2012-09-03 17:44:03 +02:00
process_stoppedrules
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-07-11 00:10:27 +02:00
our $ VERSION = 'MODULEVERSION' ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our $ 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 () {
2012-03-10 01:16:25 +01:00
if ( my $ fn = open_file 'tos' ) {
2009-02-22 18:30:14 +01:00
my $ first_entry = 1 ;
my ( $ pretosref , $ outtosref ) ;
2012-04-24 23:52:57 +02:00
first_entry ( sub { progress_message2 "$doing $fn..." ;
2015-08-21 00:35:03 +02:00
warning_message "Use of the tos file is no longer supported -- use the TOS target in the mangle file instead" ;
2012-03-10 01:16:25 +01:00
}
) ;
2009-02-22 18:30:14 +01:00
2015-08-21 00:35:03 +02:00
while ( read_a_line ( NORMAL_READ ) ) { 1 ; }
2009-02-22 18:30:14 +01:00
}
}
#
# Setup ECN disabling rules
#
sub setup_ecn ()
{
my % interfaces ;
my @ hosts ;
2016-04-02 00:10:49 +02:00
my $ interfaceref ;
2009-02-22 18:30:14 +01:00
if ( my $ fn = open_file 'ecn' ) {
2011-08-10 18:34:15 +02:00
first_entry ( sub { progress_message2 "$doing $fn..." ;
require_capability 'MANGLE_ENABLED' , 'Entries in the ecn file' , '' ;
warning_message 'ECN will not be applied to forwarded packets' unless have_capability 'MANGLE_FORWARD' ;
} ) ;
2009-02-22 18:30:14 +01:00
2012-04-14 17:04:28 +02:00
while ( read_a_line ( NORMAL_READ ) ) {
2009-02-22 18:30:14 +01:00
2013-12-14 22:35:01 +01:00
my ( $ interface , $ hosts ) = split_line1 ( 'ecn file entry' ,
{ interface = > 0 , host = > 1 , hosts = > 1 } ,
{ } ,
2 ) ;
2009-02-22 18:30:14 +01:00
2011-10-01 18:56:25 +02:00
fatal_error 'INTERFACE must be specified' if $ interface eq '-' ;
2016-04-02 00:10:49 +02:00
fatal_error "Unknown interface ($interface)" unless $ interfaceref = known_interface ( $ interface ) ;
if ( $ interfaceref - > { root } ) {
$ interface = $ interfaceref - > { name } if $ interface eq $ interfaceref - > { physical } ;
} else {
$ interface = $ interfaceref - > { name } ;
}
2009-02-22 18:30:14 +01:00
2016-01-27 19:21:08 +01:00
my $ lineinfo = shortlineinfo ( '' ) ;
$ interfaces { $ interface } || = $ lineinfo ;
2009-02-22 18:30:14 +01:00
$ hosts = ALLIP if $ hosts eq '-' ;
for my $ host ( split_list $ hosts , 'address' ) {
validate_host ( $ host , 1 ) ;
2016-01-27 19:21:08 +01:00
push @ hosts , [ $ interface , $ lineinfo , $ host ] ;
2009-02-22 18:30:14 +01:00
}
}
if ( @ hosts ) {
2015-07-13 00:00:41 +02:00
my @ interfaces = ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys % interfaces ) ;
2009-02-22 18:30:14 +01:00
progress_message "$doing ECN control on @interfaces..." ;
for my $ interface ( @ interfaces ) {
my $ chainref = ensure_chain 'mangle' , ecn_chain ( $ interface ) ;
2016-01-23 21:31:53 +01:00
add_ijump_extended $ mangle_table - > { POSTROUTING } , j = > $ chainref , $ interfaces { $ interface } , p = > 'tcp' , imatch_dest_dev ( $ interface ) if have_capability 'MANGLE_FORWARD' ;
add_ijump_extended $ mangle_table - > { OUTPUT } , j = > $ chainref , $ interfaces { $ interface } , p = > 'tcp' , imatch_dest_dev ( $ interface ) ;
2009-02-22 18:30:14 +01:00
}
for my $ host ( @ hosts ) {
2016-02-24 18:35:13 +01:00
add_ijump_extended ( $ mangle_table - > { ecn_chain $ host - > [ 0 ] } , j = > 'ECN' , $ host - > [ 1 ] , targetopts = > '--ecn-tcp-remove' , p = > 'tcp' , imatch_dest_net ( $ host - > [ 2 ] ) ) ;
2009-02-22 18:30:14 +01:00
}
}
}
}
2015-09-07 01:08:59 +02:00
sub add_rule_pair ( $$$$$ ) {
my ( $ chainref , $ predicate , $ target , $ level , $ tag ) = @ _ ;
log_rule_limit ( $ level ,
$ chainref ,
$ chainref - > { name } ,
"\U$target" ,
$ globals { LOGLIMIT } ,
$ tag ,
'add' ,
$ predicate ) if supplied $ level ;
2010-01-16 18:53:53 +01:00
add_jump ( $ chainref , $ target , 0 , $ predicate ) ;
2009-02-22 18:30:14 +01:00
}
2011-11-08 21:59:40 +01:00
#
2012-04-24 23:52:57 +02:00
# Remove instances of 'blacklist' from the passed file.
2011-11-08 21:59:40 +01:00
#
sub remove_blacklist ( $ ) {
my $ file = shift ;
my $ fn = find_file $ file ;
2011-11-18 15:26:37 +01:00
return 1 unless - f $ file ;
2011-11-08 21:59:40 +01:00
my $ oldfile = open_file $ fn ;
my $ newfile ;
my $ changed ;
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
open $ newfile , '>' , "$fn.new" or fatal_error "Unable to open $fn.new for output: $!" ;
2012-04-11 23:28:09 +02:00
while ( read_a_line ( EMBEDDED_ENABLED | EXPAND_VARIABLES ) ) {
2011-11-08 21:59:40 +01:00
my ( $ rule , $ comment ) = split '#' , $ currentline , 2 ;
2015-08-07 22:46:16 +02:00
if ( $ rule && $ rule =~ /blacklist/ ) {
2011-11-08 21:59:40 +01:00
$ changed = 1 ;
if ( $ comment ) {
2015-08-08 21:42:32 +02:00
$ comment =~ s/^/ / while $ rule =~ s/blacklist,// || $ rule =~ s/,blacklist// ;
2011-11-08 21:59:40 +01:00
$ rule =~ s/blacklist/ /g ;
$ currentline = join ( '#' , $ rule , $ comment ) ;
} else {
2015-08-08 21:42:32 +02:00
$ currentline =~ s/blacklist,//g ;
$ currentline =~ s/,blacklist//g ;
2011-11-08 21:59:40 +01:00
$ currentline =~ s/blacklist/ /g ;
2012-04-24 23:52:57 +02:00
}
2011-11-08 21:59:40 +01:00
}
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
print $ newfile "$currentline\n" ;
}
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
close $ newfile ;
if ( $ changed ) {
rename $ fn , "$fn.bak" or fatal_error "Unable to rename $fn to $fn.bak: $!" ;
rename "$fn.new" , $ fn or fatal_error "Unable to rename $fn.new to $fn: $!" ;
2016-06-17 01:04:32 +02:00
transfer_permissions ( "$fn.bak" , $ fn ) ;
2011-11-08 21:59:40 +01:00
progress_message2 "\u$file file $fn saved in $fn.bak"
}
}
#
2015-08-09 23:31:47 +02:00
# Convert a pre-4.4.25 blacklist to a 4.4.25 blrules file
2011-11-08 21:59:40 +01:00
#
sub convert_blacklist () {
my $ zones = find_zones_by_option 'blacklist' , 'in' ;
my $ zones1 = find_zones_by_option 'blacklist' , 'out' ;
2013-02-12 16:47:02 +01:00
my ( $ level , $ disposition ) = @ config { 'BLACKLIST_LOG_LEVEL' , 'BLACKLIST_DISPOSITION' } ;
2015-09-07 01:08:59 +02:00
my $ tag = $ globals { MACLIST_LOG_TAG } ;
2011-11-08 21:59:40 +01:00
my $ audit = $ disposition =~ /^A_/ ;
2015-08-13 22:22:14 +02:00
my $ target = $ disposition ;
2011-11-08 21:59:40 +01:00
my $ orig_target = $ target ;
my @ rules ;
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
if ( @$ zones || @$ zones1 ) {
2015-09-07 01:08:59 +02:00
if ( supplied $ level ) {
$ target = supplied $ tag ? "$target:$level:$tag" : "$target:$level" ;
}
2011-11-08 21:59:40 +01:00
2015-08-09 23:31:47 +02:00
my $ fn = open_file ( 'blacklist' ) ;
unless ( $ fn ) {
if ( - f ( $ fn = find_file ( 'blacklist' ) ) ) {
if ( unlink ( $ fn ) ) {
warning_message "Empty blacklist file ($fn) removed" ;
} else {
warning_message "Unable to remove empty blacklist file $fn: $!" ;
}
}
return 0 ;
}
2011-11-08 21:59:40 +01:00
first_entry "Converting $fn..." ;
2012-04-14 17:04:28 +02:00
while ( read_a_line ( NORMAL_READ ) ) {
2013-12-14 22:35:01 +01:00
my ( $ networks , $ protocol , $ ports , $ options ) =
split_line ( 'blacklist file' ,
{ networks = > 0 , proto = > 1 , port = > 2 , options = > 3 } ) ;
2011-11-08 21:59:40 +01:00
if ( $ options eq '-' ) {
$ options = 'src' ;
} elsif ( $ options eq 'audit' ) {
$ options = 'audit,src' ;
}
my ( $ to , $ from , $ whitelist , $ auditone ) = ( 0 , 0 , 0 , 0 ) ;
my @ options = split_list $ options , 'option' ;
for ( @ options ) {
$ whitelist + + if $ _ eq 'whitelist' ;
2012-04-24 23:52:57 +02:00
$ auditone + + if $ _ eq 'audit' ;
2011-11-08 21:59:40 +01:00
}
warning_message "Duplicate 'whitelist' option ignored" if $ whitelist > 1 ;
2011-11-19 17:18:58 +01:00
my $ tgt = $ whitelist ? 'WHITELIST' : $ target ;
2011-11-08 21:59:40 +01: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 ;
}
}
for ( @ options ) {
if ( $ _ =~ /^(?:src|from)$/ ) {
if ( $ from + + ) {
warning_message "Duplicate 'src' ignored" ;
} else {
if ( @$ zones ) {
push @ rules , [ 'src' , $ tgt , $ networks , $ protocol , $ ports ] ;
} else {
warning_message '"src" entry ignored because there are no "blacklist in" zones' ;
}
}
} elsif ( $ _ =~ /^(?:dst|to)$/ ) {
if ( $ to + + ) {
warning_message "Duplicate 'dst' ignored" ;
} else {
if ( @$ zones1 ) {
push @ rules , [ 'dst' , $ tgt , $ networks , $ protocol , $ ports ] ;
} else {
warning_message '"dst" entry ignored because there are no "blacklist out" zones' ;
}
}
} else {
fatal_error "Invalid blacklist option($_)" unless $ _ eq 'whitelist' || $ _ eq 'audit' ;
}
}
}
if ( @ rules ) {
2015-08-31 20:21:18 +02:00
my $ fn1 = find_writable_file ( 'blrules' ) ;
2011-11-08 21:59:40 +01:00
my $ blrules ;
2016-05-07 22:48:16 +02:00
my $ date = compiletime ;
2011-11-08 21:59:40 +01:00
if ( - f $ fn1 ) {
open $ blrules , '>>' , $ fn1 or fatal_error "Unable to open $fn1: $!" ;
} else {
open $ blrules , '>' , $ fn1 or fatal_error "Unable to open $fn1: $!" ;
2016-06-17 01:04:32 +02:00
transfer_permissions ( $ fn , $ fn1 ) ;
2011-11-08 21:59:40 +01:00
print $ blrules << 'EOF' ;
#
2015-07-28 19:59:11 +02:00
# Shorewall version 5.0 - Blacklist Rules File
2011-11-08 21:59:40 +01:00
#
# For information about entries in this file, type "man shorewall-blrules"
#
# Please see http://shorewall.net/blacklisting_support.htm for additional
# information.
#
###################################################################################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT TIME HEADERS SWITCH
# PORT PORT(S) DEST LIMIT GROUP
EOF
}
2012-04-24 23:52:57 +02:00
print ( $ blrules
2011-11-08 21:59:40 +01:00
"#\n" ,
"# Rules generated from blacklist file $fn by Shorewall $globals{VERSION} - $date\n" ,
"#\n" ) ;
for ( @ rules ) {
my ( $ srcdst , $ tgt , $ networks , $ protocols , $ ports ) = @$ _ ;
2011-11-19 17:18:58 +01:00
$ tgt . = "\t\t" ;
2011-11-08 21:59:40 +01:00
my $ list = $ srcdst eq 'src' ? $ zones : $ zones1 ;
for my $ zone ( @$ list ) {
my $ rule = $ tgt ;
if ( $ srcdst eq 'src' ) {
if ( $ networks ne '-' ) {
$ rule . = "$zone:$networks\tall\t\t" ;
} else {
$ rule . = "$zone\t\t\tall\t\t" ;
}
} else {
if ( $ networks ne '-' ) {
$ rule . = "all\t\t\t$zone:$networks\t" ;
} else {
$ rule . = "all\t\t\t$zone\t\t\t" ;
}
}
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
$ rule . = "\t$protocols" if $ protocols ne '-' ;
$ rule . = "\t$ports" if $ ports ne '-' ;
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
print $ blrules "$rule\n" ;
}
}
close $ blrules ;
} else {
2011-11-21 21:13:39 +01:00
warning_message q( There are interfaces or zones with the 'blacklist' option but the 'blacklist' file is empty or does not exist ) unless @ rules ;
}
2012-04-24 23:52:57 +02:00
2011-11-21 21:13:39 +01:00
if ( - f $ fn ) {
rename $ fn , "$fn.bak" ;
progress_message2 "Blacklist file $fn saved in $fn.bak" ;
2011-11-08 21:59:40 +01:00
}
2012-04-24 23:52:57 +02:00
2011-11-08 21:59:40 +01:00
for my $ file ( qw( zones interfaces hosts ) ) {
remove_blacklist $ file ;
}
progress_message2 "Blacklist successfully converted" ;
2012-04-24 23:52:57 +02:00
return 1 ;
2011-11-08 21:59:40 +01:00
} else {
my $ fn = find_file 'blacklist' ;
if ( - f $ fn ) {
rename $ fn , "$fn.bak" or fatal_error "Unable to rename $fn to $fn.bak: $!" ;
warning_message "No zones have the blacklist option - the blacklist file was saved in $fn.bak" ;
}
return 0 ;
}
}
2015-08-07 22:46:16 +02:00
sub convert_routestopped () {
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( my $ fn = open_file 'routestopped' ) {
2012-09-05 02:03:02 +02:00
my ( @ allhosts , % source , % dest , % notrack , @ rule ) ;
2009-02-22 18:30:14 +01:00
2015-08-13 23:37:13 +02:00
my $ seq = 0 ;
2016-05-07 22:48:16 +02:00
my $ date = compiletime ;
2009-02-22 18:30:14 +01:00
2015-08-07 22:46:16 +02:00
my ( $ stoppedrules , $ fn1 ) ;
2015-08-31 20:21:18 +02:00
if ( - f ( $ fn1 = find_writable_file ( 'stoppedrules' ) ) ) {
2015-08-07 22:46:16 +02:00
open $ stoppedrules , '>>' , $ fn1 or fatal_error "Unable to open $fn1: $!" ;
} else {
open $ stoppedrules , '>' , $ fn1 or fatal_error "Unable to open $fn1: $!" ;
2016-06-17 01:04:32 +02:00
transfer_permissions ( $ fn , $ fn1 ) ;
2015-08-07 22:46:16 +02:00
print $ stoppedrules << 'EOF' ;
#
# Shorewall version 5 - Stopped Rules File
#
# For information about entries in this file, type "man shorewall-stoppedrules"
#
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-stoppedrules.html
#
# See http://shorewall.net/starting_and_stopping_shorewall.htm for additional
# information.
#
###############################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE
# PORT(S) PORT(S)
EOF
}
2015-08-31 20:21:18 +02:00
first_entry (
sub {
2016-05-07 22:48:16 +02:00
my $ date = compiletime ;
2015-08-31 20:21:18 +02:00
progress_message2 "$doing $fn..." ;
print ( $ stoppedrules
"#\n" ,
"# Rules generated from routestopped file $fn by Shorewall $globals{VERSION} - $date\n" ,
"#\n" ) ;
}
) ;
2009-02-22 18:30:14 +01:00
2012-04-14 17:04:28 +02:00
while ( read_a_line ( NORMAL_READ ) ) {
2009-02-22 18:30:14 +01:00
2011-09-26 02:08:53 +02:00
my ( $ interface , $ hosts , $ options , $ proto , $ ports , $ sports ) =
2013-12-14 22:35:01 +01:00
split_line ( 'routestopped file' ,
{ interface = > 0 , hosts = > 1 , options = > 2 , proto = > 3 , dport = > 4 , sport = > 5 } ) ;
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
2011-10-01 18:56:25 +02:00
fatal_error 'INTERFACE must be specified' if $ interface eq '-' ;
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
2015-08-07 22:46:16 +02:00
my $ rule = "$proto\t$ports\t$sports" ;
$ hosts = ALLIP if $ hosts eq '-' ;
2009-02-22 18:30:14 +01:00
2012-09-05 02:03:02 +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' ) {
2012-09-05 02:03:02 +02:00
for my $ host ( split /,/ , $ hosts ) {
2010-09-28 19:48:44 +02:00
$ source { "$interface|$host|$seq" } = 1 ;
}
} elsif ( $ option eq 'dest' ) {
2012-09-05 02:03:02 +02:00
for my $ host ( split /,/ , $ hosts ) {
2010-09-28 19:48:44 +02:00
$ 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
2012-09-05 02:03:02 +02:00
for my $ host ( split /,/ , $ hosts ) {
2015-08-07 22:46:16 +02:00
print $ stoppedrules "ACCEPT\t$interface:$host\t$interface:$host\n" ;
2010-09-28 19:48:44 +02:00
}
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 ;
2015-08-07 22:46:16 +02:00
my $ rule = shift @ rule ;
2009-02-22 18:30:14 +01:00
2015-08-07 22:46:16 +02:00
print $ stoppedrules "ACCEPT\t$interface:$h\t\$FW\t$rule\n" ;
print $ stoppedrules "ACCEPT\t\$FW\t$interface:$h\t$rule\n" 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 } ) {
2015-08-07 22:46:16 +02:00
print $ stoppedrules "ACCEPT\t$interface:$h\t-\t$rule\n" ;
2010-09-28 19:48:44 +02:00
$ matched = 1 ;
}
2009-02-22 18:30:14 +01:00
2012-09-05 02:03:02 +02:00
if ( $ dest { $ host } ) {
2015-08-07 22:46:16 +02:00
print $ stoppedrules "ACCEPT\t-\t$interface:$h\t$rule\n" ;
2010-09-28 19:48:44 +02:00
$ matched = 1 ;
}
2009-02-22 18:30:14 +01:00
2010-09-28 19:48:44 +02:00
if ( $ notrack { $ host } ) {
2015-08-07 22:46:16 +02:00
print $ stoppedrules "NOTRACK\t$interface:$h\t-\t$rule\n" ;
2015-08-08 21:42:32 +02:00
print $ stoppedrules "NOTRACK\t\$FW\t$interface:$h\t$rule\n" ;
2010-09-28 19:48:44 +02:00
}
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 ;
2015-08-07 22:46:16 +02:00
print $ stoppedrules "ACCEPT\t$interface:$h\t$interface1:$h1\t$rule\n" ;
2010-09-28 19:48:44 +02:00
}
2009-02-22 18:30:14 +01:00
}
}
}
2015-08-07 22:46:16 +02:00
rename $ fn , "$fn.bak" ;
progress_message2 "Routestopped file $fn saved in $fn.bak" ;
close $ stoppedrules ;
2015-08-09 23:31:47 +02:00
} elsif ( - f ( my $ fn1 = find_file ( 'routestopped' ) ) ) {
if ( unlink ( $ fn1 ) ) {
warning_message "Empty routestopped file ($fn1) removed" ;
} else {
warning_message "Unable to remove empty routestopped file $fn1: $!" ;
}
2009-02-22 18:30:14 +01:00
}
}
2012-09-03 17:44:03 +02:00
#
2012-09-04 17:46:04 +02:00
# Process the stoppedrules file. Returns true if the file was non-empty.
2012-09-03 17:44:03 +02:00
#
sub process_stoppedrules () {
my $ fw = firewall_zone ;
2012-09-04 17:46:04 +02:00
my $ result ;
2012-09-03 17:44:03 +02:00
2012-12-23 00:47:03 +01:00
if ( my $ fn = open_file 'stoppedrules' , 1 , 1 ) {
2014-09-25 17:03:35 +02:00
first_entry sub () {
progress_message2 ( "$doing $fn..." ) ;
2014-03-05 17:57:03 +01:00
unless ( $ config { ADMINISABSENTMINDED } ) {
2014-09-25 17:03:35 +02:00
insert_ijump $ filter_table - > { $ _ } , j = > 'ACCEPT' , 0 , state_imatch 'ESTABLISHED,RELATED' for qw/INPUT FORWARD/ ;
2014-03-05 17:57:03 +01:00
}
} ;
2012-09-03 17:44:03 +02:00
while ( read_a_line ( NORMAL_READ ) ) {
2012-09-04 17:46:04 +02:00
$ result = 1 ;
2013-01-08 01:06:54 +01:00
my ( $ target , $ source , $ dest , $ protos , $ ports , $ sports ) =
2013-12-14 22:35:01 +01:00
split_line1 ( 'stoppedrules file' ,
{ target = > 0 , source = > 1 , dest = > 2 , proto = > 3 , dport = > 4 , sport = > 5 } ) ;
2012-09-04 17:46:04 +02:00
2014-01-07 22:19:49 +01:00
fatal_error ( "Invalid TARGET ($target)" ) unless $ target =~ /^(?:ACCEPT|DROP|NOTRACK)$/ ;
2012-09-03 17:44:03 +02:00
my $ tableref ;
2014-01-07 22:19:49 +01:00
my $ raw ;
2012-09-03 17:44:03 +02:00
my $ chainref ;
my $ restriction = NO_RESTRICT ;
2014-01-07 22:19:49 +01:00
if ( $ raw = ( $ target eq 'NOTRACK' || $ target eq 'DROP' ) ) {
2012-09-03 17:44:03 +02:00
$ tableref = $ raw_table ;
require_capability 'RAW_TABLE' , 'NOTRACK' , 's' ;
$ chainref = $ raw_table - > { PREROUTING } ;
$ restriction = PREROUTE_RESTRICT | DESTIFACE_DISALLOW ;
} else {
$ tableref = $ filter_table ;
}
2012-09-04 17:46:04 +02:00
2012-09-03 17:44:03 +02:00
if ( $ source eq $ fw ) {
2014-01-07 22:19:49 +01:00
$ chainref = ( $ raw ? $ raw_table : $ filter_table ) - > { OUTPUT } ;
2012-09-03 17:44:03 +02:00
$ source = '' ;
$ restriction = OUTPUT_RESTRICT ;
2012-11-23 17:35:51 +01:00
} elsif ( $ source =~ s/^($fw):// ) {
2014-01-07 22:19:49 +01:00
$ chainref = ( $ raw ? $ raw_table : $ filter_table ) - > { OUTPUT } ;
2012-09-03 17:44:03 +02:00
$ restriction = OUTPUT_RESTRICT ;
}
if ( $ dest eq $ fw ) {
2014-01-07 22:19:49 +01:00
fatal_error "\$FW may not be specified as the destination of a NOTRACK or DROP rule" if $ raw ;
2012-09-03 17:44:03 +02:00
$ chainref = $ filter_table - > { INPUT } ;
$ dest = '' ;
$ restriction = INPUT_RESTRICT ;
2012-11-23 17:35:51 +01:00
} elsif ( $ dest =~ s/^($fw):// ) {
2014-01-07 22:19:49 +01:00
fatal_error "\$FW may not be specified as the destination of a NOTRACK or DROP rule" if $ raw ;
2012-09-03 17:44:03 +02:00
$ chainref = $ filter_table - > { INPUT } ;
$ restriction = INPUT_RESTRICT ;
}
$ chainref = $ tableref - > { FORWARD } unless $ chainref ;
my $ disposition = $ target ;
2012-09-04 17:46:04 +02:00
2012-09-03 17:44:03 +02:00
$ target = 'CT --notrack' if $ target eq 'NOTRACK' and have_capability ( 'CT_TARGET' ) ;
unless ( $ restriction == OUTPUT_RESTRICT
&& $ target eq 'ACCEPT'
&& $ config { ADMINISABSENTMINDED } ) {
2013-01-08 01:06:54 +01:00
for my $ proto ( split_list $ protos , 'Protocol' ) {
expand_rule ( $ chainref ,
$ restriction ,
2013-04-20 17:02:02 +02:00
'' ,
2013-01-08 01:06:54 +01:00
do_proto ( $ proto , $ ports , $ sports ) ,
$ source ,
$ dest ,
'' ,
$ target ,
'' ,
$ disposition ,
2016-01-04 22:10:03 +01:00
do_proto ( $ proto , '-' , '-' ) ,
'' ) ;
2013-01-08 01:06:54 +01:00
}
2012-09-05 16:16:40 +02:00
} else {
warning_message "Redundant OUTPUT rule ignored because ADMINISABSENTMINDED=Yes" ;
2012-09-03 17:44:03 +02:00
}
}
}
2012-09-04 17:46:04 +02:00
$ result ;
2012-09-03 17:44:03 +02:00
}
2016-02-21 19:33:45 +01:00
sub create_docker_rules () {
2016-02-22 23:46:35 +01:00
add_commands ( $ nat_table - > { PREROUTING } , '[ -n "$g_docker" ] && echo "-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER" >&3' ) ;
2016-02-21 19:33:45 +01:00
2016-02-27 22:36:47 +01:00
my $ chainref = $ filter_table - > { FORWARD } ;
add_commands ( $ chainref , '[ -n "$g_dockernetwork" ] && echo "-A FORWARD -j DOCKER-ISOLATION" >&3' , ) ;
2016-02-22 23:46:35 +01:00
2016-03-04 18:27:47 +01:00
if ( my $ dockerref = known_interface ( 'docker0' ) ) {
add_commands ( $ chainref , 'if [ -n "$g_docker" ]; then' ) ;
incr_cmd_level ( $ chainref ) ;
add_ijump ( $ chainref , j = > 'DOCKER' , o = > 'docker0' ) ;
2016-04-18 19:13:05 +02:00
add_ijump ( $ chainref , j = > 'ACCEPT' , o = > 'docker0' , state_imatch 'ESTABLISHED,RELATED' ) ;
2016-03-04 18:27:47 +01:00
add_ijump ( $ chainref , j = > 'ACCEPT' , i = > 'docker0' , o = > '! docker0' ) ;
add_ijump ( $ chainref , j = > 'ACCEPT' , i = > 'docker0' , o = > 'docker0' ) if $ dockerref - > { options } { routeback } ;
decr_cmd_level ( $ chainref ) ;
add_commands ( $ chainref , 'fi' ) ;
2016-05-23 02:50:51 +02:00
my $ outputref ;
add_commands ( $ outputref = $ filter_table - > { OUTPUT } , 'if [ -n "$g_docker" ]; then' ) ;
incr_cmd_level ( $ outputref ) ;
add_ijump ( $ outputref , j = > 'DOCKER' ) ;
decr_cmd_level ( $ outputref ) ;
add_commands ( $ outputref , 'fi' ) ;
2016-02-21 19:33:45 +01:00
}
2016-02-27 22:36:47 +01:00
2016-03-03 23:11:57 +01:00
add_commands ( $ chainref , '[ -f ${VARDIR}/.filter_FORWARD ] && cat $VARDIR/.filter_FORWARD >&3' , ) ;
2016-02-21 19:33:45 +01:00
}
2009-02-22 18:30:14 +01:00
sub setup_mss () ;
2015-08-31 23:21:41 +02:00
sub add_common_rules ( $ ) {
my ( $ upgrade ) = @ _ ;
2009-02-22 18:30:14 +01:00
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
2013-01-30 17:00:47 +01:00
my @ state = state_imatch ( $ globals { BLACKLIST_STATES } ) ;
2011-12-07 04:04:43 +01:00
my $ faststate = $ config { RELATED_DISPOSITION } eq 'ACCEPT' && $ config { RELATED_LOG_LEVEL } eq '' ? 'ESTABLISHED,RELATED' : 'ESTABLISHED' ;
2013-02-12 16:47:02 +01:00
my $ level = $ config { BLACKLIST_LOG_LEVEL } ;
2015-09-07 01:08:59 +02:00
my $ tag = $ globals { BLACKLIST_LOG_TAG } ;
2011-05-24 05:59:33 +02:00
my $ rejectref = $ filter_table - > { reject } ;
2016-04-11 01:07:56 +02:00
my $ dbl_type ;
my $ dbl_ipset ;
my $ dbl_level ;
my $ dbl_tag ;
my $ dbl_target ;
2016-04-07 17:48:36 +02:00
if ( $ config { REJECT_ACTION } ) {
process_reject_action ;
2016-04-07 18:34:38 +02:00
fatal_eror ( "The REJECT_ACTION ($config{REJECT_ACTION}) is not terminating" ) unless terminating ( $ rejectref ) ;
2016-04-07 17:48:36 +02:00
} else {
if ( have_capability ( 'ADDRTYPE' ) ) {
add_ijump $ rejectref , j = > 'DROP' , addrtype = > '--src-type BROADCAST' ;
} else {
if ( $ family == F_IPV4 ) {
add_commands $ rejectref , 'for address in $ALL_BCASTS; do' ;
} else {
add_commands $ rejectref , 'for address in $ALL_ACASTS; do' ;
}
incr_cmd_level $ rejectref ;
add_ijump $ rejectref , j = > 'DROP' , d = > '$address' ;
decr_cmd_level $ rejectref ;
add_commands $ rejectref , 'done' ;
}
if ( $ family == F_IPV4 ) {
add_ijump $ rejectref , j = > 'DROP' , s = > '224.0.0.0/4' ;
} else {
add_ijump $ rejectref , j = > 'DROP' , s = > IPv6_MULTICAST ;
}
add_ijump $ rejectref , j = > 'DROP' , p = > 2 ;
add_ijump $ rejectref , j = > 'REJECT' , targetopts = > '--reject-with tcp-reset' , p = > 6 ;
if ( have_capability ( 'ENHANCED_REJECT' ) ) {
add_ijump $ rejectref , j = > 'REJECT' , p = > 17 ;
if ( $ family == F_IPV4 ) {
add_ijump $ rejectref , j = > 'REJECT --reject-with icmp-host-unreachable' , p = > 1 ;
add_ijump $ rejectref , j = > 'REJECT --reject-with icmp-host-prohibited' ;
} else {
add_ijump $ rejectref , j = > 'REJECT --reject-with icmp6-addr-unreachable' , p = > 58 ;
add_ijump $ rejectref , j = > 'REJECT --reject-with icmp6-adm-prohibited' ;
}
} else {
add_ijump $ rejectref , j = > 'REJECT' ;
}
}
2016-02-20 23:01:48 +01:00
#
# Insure that Docker jumps are early in the builtin chains
#
2016-02-21 19:33:45 +01:00
create_docker_rules if $ config { DOCKER } ;
2009-02-22 18:30:14 +01:00
2016-04-11 01:07:56 +02:00
if ( my $ val = $ config { DYNAMIC_BLACKLIST } ) {
( $ dbl_type , $ dbl_ipset , $ dbl_level , $ dbl_tag ) = split ( ':' , $ val ) ;
unless ( $ dbl_type =~ /^ipset-only/ ) {
add_rule_pair ( set_optflags ( new_standard_chain ( 'logdrop' ) , DONT_OPTIMIZE | DONT_DELETE ) , '' , 'DROP' , $ level , $ tag ) ;
add_rule_pair ( set_optflags ( new_standard_chain ( 'logreject' ) , DONT_OPTIMIZE | DONT_DELETE ) , '' , 'reject' , $ level , $ tag ) ;
$ dynamicref = set_optflags ( new_standard_chain ( 'dynamic' ) , DONT_OPTIMIZE ) ;
add_commands ( $ dynamicref , '[ -f ${VARDIR}/.dynamic ] && cat ${VARDIR}/.dynamic >&3' ) ;
}
if ( $ dbl_ipset ) {
if ( $ dbl_level ) {
my $ chainref = set_optflags ( new_standard_chain ( $ dbl_target = 'dbl_log' ) , DONT_OPTIMIZE | DONT_DELETE ) ;
log_rule_limit ( $ dbl_level ,
$ chainref ,
'dbl_log' ,
'DROP' ,
$ globals { LOGLIMIT } ,
$ dbl_tag ,
'add' ,
'' ,
$ origin { DYNAMIC_BLACKLIST } ) ;
add_ijump_extended ( $ chainref , j = > 'DROP' , $ origin { DYNAMIC_BLACKLIST } ) ;
} else {
$ dbl_target = 'DROP' ;
}
}
2010-01-16 18:53:53 +01:00
}
2009-02-22 18:30:14 +01:00
setup_mss ;
2011-12-06 01:08:17 +01:00
if ( $ config { FASTACCEPT } ) {
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ filter_table - > { OUTPUT } , j = > 'ACCEPT' , $ origin { FASTACCEPT } , state_imatch $ faststate )
2012-04-24 23:52:57 +02:00
}
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 } ;
2015-09-07 01:08:59 +02:00
$ tag = $ config { SFILTER_LOG_TAG } ;
2011-05-26 22:38:44 +02:00
my $ audit = $ policy =~ s/^A_// ;
2011-07-18 00:12:58 +02:00
my @ ipsec = have_ipsec ? ( policy = > '--pol none --dir in' ) : ( ) ;
2016-01-26 00:49:18 +01:00
my $ origin = $ origin { SFILTER_DISPOSITION } ;
2011-05-26 22:38:44 +02:00
2011-09-01 23:15:15 +02:00
if ( $ level || $ audit ) {
#
2011-09-02 17:41:42 +02:00
# Create a chain to log and/or audit and apply the policy
2011-09-01 23:15:15 +02:00
#
2011-05-28 04:42:09 +02:00
$ chainref = new_standard_chain 'sfilter' ;
2011-05-26 22:38:44 +02:00
2016-01-27 23:24:56 +01:00
log_rule_limit ( $ level ,
$ chainref ,
$ chainref - > { name } ,
$ policy ,
$ globals { LOGLIMIT } ,
$ tag ,
'add' ,
'' ,
$ origin { SFILTER_LOG_LEVEL } ) if $ level ne '' ;
2012-04-24 23:52:57 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , j = > 'AUDIT' , $ origin , targetopts = > '--type ' . lc $ policy ) if $ audit ;
2012-04-24 23:52:57 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ policy eq 'REJECT' ? 'reject' : $ policy , $ origin ) ;
2012-04-24 23:52:57 +02:00
2011-05-28 04:42:09 +02:00
$ target = 'sfilter' ;
2011-09-02 17:41:42 +02:00
} else {
$ target = $ policy eq 'REJECT' ? 'reject' : $ policy ;
2011-09-01 23:15:15 +02:00
}
2011-06-09 18:57:45 +02:00
2011-09-01 23:15:15 +02:00
if ( @ ipsec ) {
#
# sfilter1 will be used in the FORWARD chain where we allow traffic entering the interface
# to leave the interface encrypted. We need a separate chain because '--dir out' cannot be
# used in the input chain
#
$ chainref = new_standard_chain 'sfilter1' ;
2011-06-09 18:57:45 +02:00
2011-09-01 23:15:15 +02:00
add_ijump ( $ chainref , j = > 'RETURN' , policy = > '--pol ipsec --dir out' ) ;
2012-04-24 23:52:57 +02:00
2016-01-27 23:24:56 +01:00
log_rule_limit ( $ level ,
$ chainref ,
$ chainref - > { name } ,
$ policy ,
$ globals { LOGLIMIT } ,
$ tag ,
'add' ,
'' ,
$ origin ) if $ level ne '' ;
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , j = > 'AUDIT' , $ origin { SFILTER_DISPOSITION } , targetopts = > '--type ' . lc $ policy ) if $ audit ;
2012-04-24 23:52:57 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ policy eq 'REJECT' ? 'reject' : $ policy , $ origin ) ;
2012-04-24 23:52:57 +02:00
2011-09-01 23:15:15 +02:00
$ target1 = 'sfilter1' ;
} else {
#
# No IPSEC -- use the same target in both INPUT and FORWARD
#
$ target1 = $ target ;
2009-02-22 18:30:14 +01:00
}
2012-02-01 19:25:26 +01:00
for $ interface ( all_real_interfaces ) {
2013-07-24 16:22:51 +02:00
ensure_chain ( 'filter' , $ _ ) - > { origin } = interface_origin ( $ interface )
for first_chains ( $ interface ) , output_chain ( $ interface ) , option_chains ( $ interface ) , output_option_chain ( $ interface ) ;
2011-05-26 22:38:44 +02:00
my $ interfaceref = find_interface $ interface ;
2015-01-03 18:22:40 +01:00
unless ( $ interfaceref - > { physical } eq loopback_interface ) {
2014-03-31 16:28:30 +02:00
unless ( $ interfaceref - > { options } { ignore } & NO_SFILTER || $ interfaceref - > { options } { rpfilter } ) {
2011-05-26 22:38:44 +02:00
2014-03-31 16:28:30 +02:00
my @ filters = @ { $ interfaceref - > { filter } } ;
2016-01-23 21:31:53 +01:00
my $ origin = $ interfaceref - > { origin } ;
2012-04-24 23:52:57 +02:00
2014-03-31 16:28:30 +02:00
$ chainref = $ filter_table - > { forward_option_chain $ interface } ;
2012-04-24 23:52:57 +02:00
2014-03-31 16:28:30 +02:00
if ( @ filters ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , @ ipsec ? 'j' : 'g' = > $ target1 , $ origin , imatch_source_net ( $ _ ) , @ ipsec ) , $ chainref - > { filtered } + + for @ filters ;
2014-03-31 16:28:30 +02:00
} elsif ( $ interfaceref - > { bridge } eq $ interface ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , @ ipsec ? 'j' : 'g' = > $ target1 , $ origin , imatch_dest_dev ( $ interface ) , @ ipsec ) , $ chainref - > { filtered } + +
2014-03-31 16:28:30 +02:00
unless ( $ config { ROUTE_FILTER } eq 'on' ||
$ interfaceref - > { options } { routeback } ||
$ interfaceref - > { options } { routefilter } ||
$ interfaceref - > { physical } eq '+' ) ;
}
2011-06-09 18:57:45 +02:00
2012-04-24 23:52:57 +02:00
2014-03-31 16:28:30 +02:00
if ( @ filters ) {
$ chainref = $ filter_table - > { input_option_chain $ interface } ;
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , g = > $ target , $ origin , imatch_source_net ( $ _ ) , @ ipsec ) , $ chainref - > { filtered } + + for @ filters ;
2014-03-31 16:28:30 +02:00
}
2011-05-26 22:38:44 +02:00
}
2014-06-06 19:44:33 +02:00
2016-06-16 01:35:41 +02:00
if ( $ dbl_ipset && ( ( my $ setting = get_interface_option ( $ interface , 'dbl' ) ) ne '0:0' ) ) {
my ( $ in , $ out ) = split /:/ , $ setting ;
if ( $ in == 1 ) {
#
# src
#
add_ijump_extended ( $ filter_table - > { input_option_chain ( $ interface ) } , j = > $ dbl_target , $ origin { DYNAMIC_BLACKLIST } , @ state , set = > "--match-set $dbl_ipset src" ) ;
add_ijump_extended ( $ filter_table - > { forward_option_chain ( $ interface ) } , j = > $ dbl_target , $ origin { DYNAMIC_BLACKLIST } , @ state , set = > "--match-set $dbl_ipset src" ) ;
} elsif ( $ in == 2 ) {
add_ijump_extended ( $ filter_table - > { forward_option_chain ( $ interface ) } , j = > $ dbl_target , $ origin { DYNAMIC_BLACKLIST } , @ state , set = > "--match-set $dbl_ipset dst" ) ;
}
if ( $ out == 2 ) {
#
# dst
#
add_ijump_extended ( $ filter_table - > { output_option_chain ( $ interface ) } , j = > $ dbl_target , $ origin { DYNAMIC_BLACKLIST } , @ state , set = > "--match-set $dbl_ipset dst" ) ;
}
2016-04-11 01:07:56 +02:00
}
2014-06-06 22:12:02 +02:00
for ( option_chains ( $ interface ) ) {
2016-06-16 01:35:41 +02:00
add_ijump_extended ( $ filter_table - > { $ _ } , j = > $ dynamicref , $ origin { DYNAMIC_BLACKLIST } , @ state ) if $ dynamicref && ( get_interface_option ( $ interface , 'dbl' ) ne '0:0' ) ;
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ filter_table - > { $ _ } , j = > 'ACCEPT' , $ origin { FASTACCEPT } , state_imatch $ faststate ) - > { comment } = '' if $ config { FASTACCEPT } ;
2014-06-06 22:12:02 +02:00
}
2011-05-26 22:38:44 +02:00
}
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
2012-07-15 19:05:32 +02:00
$ list = find_interfaces_by_option ( 'rpfilter' ) ;
if ( @$ list ) {
$ policy = $ config { RPFILTER_DISPOSITION } ;
$ level = $ config { RPFILTER_LOG_LEVEL } ;
2015-09-07 01:08:59 +02:00
$ tag = $ globals { RPFILTER_LOG_TAG } ;
2012-07-15 19:05:32 +02:00
$ audit = $ policy =~ s/^A_// ;
2016-01-26 00:49:18 +01:00
my $ origin
= $ origin { RPFILTER_DISPOSITION } ;
2012-07-15 19:05:32 +02:00
if ( $ level || $ audit ) {
#
# Create a chain to log and/or audit and apply the policy
#
$ chainref = ensure_mangle_chain 'rplog' ;
2016-01-27 23:24:56 +01:00
log_rule_limit ( $ level ,
$ chainref ,
$ chainref - > { name } ,
$ policy ,
$ globals { LOGLIMIT } ,
$ tag ,
'add' ,
'' ,
$ origin { RPFILTER_LOG_LEVEL } ) ;
2012-07-15 19:05:32 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , j = > 'AUDIT' , $ origin , targetopts = > '--type ' . lc $ policy ) if $ audit ;
2012-07-15 19:05:32 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ policy eq 'REJECT' ? 'reject' : $ policy , $ origin ) ;
2012-07-15 19:05:32 +02:00
$ target = 'rplog' ;
} else {
$ target = $ policy eq 'REJECT' ? 'reject' : $ policy ;
}
2015-07-03 19:03:03 +02:00
my $ rpfilterref = ensure_mangle_chain ( 'rpfilter' ) ;
2015-07-03 21:21:04 +02:00
if ( $ family == F_IPV4 ) {
for $ interface ( @$ list ) {
if ( get_interface_option ( $ interface , 'dhcp' ) ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ rpfilterref ,
j = > 'RETURN' ,
get_interface_origin ( $ interface ) ,
s = > NILIPv4 ,
p = > UDP ,
dport = > 67 ,
sport = > 68
2015-07-03 21:21:04 +02:00
) ;
last ;
}
}
}
2015-07-03 19:03:03 +02:00
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ rpfilterref ,
j = > $ target ,
$ origin ,
rpfilter = > '--validmark --invert' ,
state_imatch 'NEW,RELATED,INVALID' ,
@ ipsec
2015-07-03 19:03:03 +02:00
) ;
2012-07-15 19:05:32 +02:00
}
2009-02-22 18:30:14 +01:00
run_user_exit1 'initdone' ;
2015-08-31 23:21:41 +02:00
if ( $ upgrade ) {
convert_blacklist ;
2015-08-09 23:31:47 +02:00
} elsif ( - f ( my $ fn = find_file 'blacklist' ) ) {
2015-10-05 17:19:09 +02:00
warning_message "The blacklist file is no longer supported -- use '$product update' to convert $fn to the equivalent blrules file" ;
2011-11-08 21:59:40 +01:00
}
2009-02-22 18:30:14 +01:00
$ 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 } ;
2016-01-26 00:49:18 +01:00
my $ origin = $ origin { SMURF_DISPOSITION } ;
2010-02-04 00:03:15 +01:00
2011-06-12 01:14:31 +02:00
if ( supplied $ config { SMURF_LOG_LEVEL } ) {
2011-05-22 00:02:04 +02:00
my $ smurfref = new_chain ( 'filter' , 'smurflog' ) ;
2010-06-07 16:30:56 +02:00
2016-01-27 23:24:56 +01:00
log_irule_limit ( $ config { SMURF_LOG_LEVEL } ,
$ smurfref ,
'smurfs' ,
'DROP' ,
$ globals { LOGILIMIT } ,
$ globals { SMURF_LOG_TAG } ,
'add' ,
$ origin { SMURF_LOG_LEVEL } ) ;
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ smurfref , j = > 'AUDIT' , $ origin , targetopts = > '--type drop' ) if $ smurfdest eq 'A_DROP' ;
add_ijump_extended ( $ smurfref , j = > 'DROP' , $ origin ) ;
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 ) {
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , s = > '0.0.0.0' ; ;
2010-02-07 17:43:31 +01:00
} else {
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , s = > '::' ;
2010-02-07 17:43:31 +01:00
}
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ smurfdest , $ origin , addrtype = > '--src-type BROADCAST' ) ;
2010-02-04 00:03:15 +01:00
} 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 ;
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ smurfdest , $ origin , s = > '$address' ) ;
2010-02-04 00:03:15 +01:00
decr_cmd_level $ chainref ;
add_commands $ chainref , 'done' ;
}
2009-02-22 18:30:14 +01:00
if ( $ family == F_IPV4 ) {
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ smurfdest , $ origin , s = > '224.0.0.0/4' ) ;
2009-02-22 18:30:14 +01:00
} else {
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ chainref , g = > $ smurfdest , $ origin , s = > IPv6_MULTICAST ) ;
2009-02-22 18:30:14 +01:00
}
2012-08-08 16:23:20 +02:00
my @ state = have_capability ( 'RAW_TABLE' ) ? state_imatch 'NEW,INVALID,UNTRACKED' : state_imatch '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 ] ;
2016-01-23 21:31:53 +01:00
my $ net = $ hostref - > [ 2 ] ;
2014-09-11 19:17:01 +02:00
my @ policy = $ ipsec && have_ipsec ? ( policy = > "--pol $ipsec --dir in" ) : ( ) ;
2010-02-04 00:03:15 +01:00
my $ target = source_exclusion ( $ hostref - > [ 3 ] , $ chainref ) ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > [ 5 ] ;
2010-02-04 00:03:15 +01:00
2011-12-28 03:12:58 +01:00
for $ chain ( option_chains $ interface ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ filter_table - > { $ chain } , j = > $ target , $ origin , @ state , imatch_source_net ( $ net ) , @ policy ) ;
2010-02-04 00:03:15 +01:00
}
}
2009-02-22 18:30:14 +01:00
}
$ 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 ) {
2016-01-23 21:31:53 +01:00
my $ origin = get_interface_origin ( $ interface ) ;
set_rule_option ( add_ijump_extended ( $ filter_table - > { $ _ } ,
j = > 'ACCEPT' ,
$ origin ,
p = > "udp --dport $ports" ) ,
2011-07-17 01:31:29 +02:00
'dhcp' ,
2011-12-29 17:22:00 +01:00
1 ) for input_option_chain ( $ interface ) , output_option_chain ( $ interface ) ;
2009-02-22 18:30:14 +01:00
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ filter_table - > { forward_option_chain $ interface } ,
j = > 'ACCEPT' ,
$ origin ,
p = > "udp --dport $ports" ,
imatch_dest_dev ( $ interface ) )
2009-11-06 22:10:19 +01:00
if get_interface_option ( $ interface , 'bridge' ) ;
2012-03-31 18:30:29 +02:00
unless ( $ family == F_IPV6 || get_interface_option ( $ interface , 'allip' ) ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ filter_table - > { input_chain ( $ interface ) } ,
j = > 'ACCEPT' ,
$ origin ,
p = > "udp --dport $ports" ,
s = > NILIPv4 . '/' . VLSMv4 ) ;
2012-03-31 18:30:29 +02:00
}
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 } ;
2015-09-07 01:08:59 +02:00
my $ tag = $ globals { TCP_FLAGS_LOG_TAG } ;
2011-05-21 18:25:58 +02:00
my $ disposition = $ config { TCP_FLAGS_DISPOSITION } ;
2011-05-22 00:02:04 +02:00
my $ audit = $ disposition =~ /^A_/ ;
2016-01-26 00:49:18 +01:00
my $ origin = $ origin { TCP_FLAGS_DISPOSITION } ;
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
2016-01-27 23:24:56 +01:00
log_rule_limit ( $ level ,
$ logflagsref ,
'logflags' ,
$ disposition ,
$ globals { LOGLIMIT } ,
$ tag ,
'add' ,
'' ,
$ origin { TCP_FLAGS_LOG_LEVEL } ) ;
2012-04-24 23:52:57 +02:00
2011-05-22 00:02:04 +02:00
$ globals { LOGPARMS } = $ savelogparms ;
2009-02-22 18:30:14 +01:00
2011-05-22 00:02:04 +02:00
if ( $ audit ) {
$ disposition =~ s/^A_// ;
2016-01-26 00:49:18 +01:00
add_ijump_extended ( $ logflagsref , j = > 'AUDIT' , $ origin , targetopts = > '--type ' . lc $ disposition ) ;
2011-05-21 18:25:58 +02:00
}
2011-05-22 00:02:04 +02:00
if ( $ disposition eq 'REJECT' ) {
2016-01-26 00:49:18 +01:00
add_ijump_extended $ logflagsref , j = > 'REJECT' , $ origin , targetopts = > '--reject-with tcp-reset' , p = > 6 ;
2009-02-22 18:30:14 +01:00
} else {
2016-01-26 00:49:18 +01:00
add_ijump_extended $ logflagsref , j = > $ disposition , $ origin ;
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
}
2011-07-18 00:12:58 +02:00
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags ALL FIN,URG,PSH' ;
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags ALL NONE' ;
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags SYN,RST SYN,RST' ;
2015-09-06 20:49:29 +02:00
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags FIN,RST FIN,RST' ;
2011-07-18 00:12:58 +02:00
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags SYN,FIN SYN,FIN' ;
2015-09-08 00:46:14 +02:00
add_ijump $ chainref , g = > $ disposition , p = > 'tcp --tcp-flags ACK,PSH,FIN PSH,FIN' ;
2011-07-18 00:12:58 +02:00
add_ijump $ chainref , g = > $ disposition , 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 ) ;
2014-09-11 19:17:01 +02:00
my $ ipsec = $ hostref - > [ 1 ] ;
my @ policy = $ ipsec && have_ipsec ? ( policy = > "--pol $ipsec --dir in" ) : ( ) ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > [ 5 ] ;
2009-02-22 18:30:14 +01:00
2011-12-28 03:12:58 +01:00
for $ chain ( option_chains $ interface ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ filter_table - > { $ chain } , j = > $ target , $ origin , p = > 'tcp' , imatch_source_net ( $ hostref - > [ 2 ] ) , @ policy ) ;
2009-02-22 18:30:14 +01:00
}
}
}
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" ;
2012-02-19 23:20:09 +01:00
$ chainref = set_optflags ( new_nat_chain ( 'UPnP' ) , DONT_OPTIMIZE ) ;
2010-06-06 22:10:28 +02:00
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
2016-04-01 17:57:08 +02:00
my $ chainref1 ;
if ( $ config { MINIUPNPD } ) {
$ chainref1 = set_optflags ( new_nat_chain ( 'MINIUPNPD-POSTROUTING' ) , DONT_OPTIMIZE ) ;
add_commands ( $ chainref , '[ -s /${VARDIR}/.MINIUPNPD-POSTROUTING ] && cat ${VARDIR}/.MINIUPNPD-POSTROUTING >&3' ) ;
}
2009-06-15 22:34:35 +02:00
$ announced = 1 ;
2009-02-22 18:30:14 +01:00
for $ interface ( @$ list ) {
2016-04-11 18:02:44 +02:00
add_ijump_extended $ nat_table - > { PREROUTING } , j = > 'UPnP' , get_interface_origin ( $ interface ) , imatch_source_dev ( $ interface ) ;
add_ijump_extended $ nat_table - > { $ globals { POSTROUTING } } , j = > 'MINIUPNPD-POSTROUTING' , $ origin { MINIUPNPD } , imatch_dest_dev ( $ interface ) if $ chainref1 ;
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 ) {
2011-12-28 03:12:58 +01:00
my $ chainref = $ filter_table - > { input_option_chain $ interface } ;
2012-12-28 19:39:19 +01:00
my $ base = uc var_base get_physical $ interface ;
2012-02-24 18:02:04 +01:00
my $ optional = interface_is_optional ( $ interface ) ;
my $ variable = get_interface_gateway ( $ interface , ! $ optional ) ;
2016-01-23 21:31:53 +01:00
my $ origin = get_interface_origin ( $ interface ) ;
2009-06-15 22:34:35 +02:00
2012-02-24 18:02:04 +01:00
if ( $ optional ) {
2009-08-20 23:32:15 +02:00
add_commands ( $ chainref ,
2011-07-17 01:31:29 +02:00
qq( if [ -n "SW_\$${base}_IS_USABLE" -a -n "$variable" ]; then ) ) ;
incr_cmd_level ( $ chainref ) ;
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , j = > 'ACCEPT' , $ origin , imatch_source_dev ( $ interface ) , s = > $ variable , p = > 'udp' ) ;
2011-07-17 01:31:29 +02:00
decr_cmd_level ( $ chainref ) ;
add_commands ( $ chainref , 'fi' ) ;
2009-08-11 17:31:58 +02:00
} else {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , j = > 'ACCEPT' , $ origin , imatch_source_dev ( $ interface ) , s = > $ variable , p = > 'udp' ) ;
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 } ;
2015-09-07 01:08:59 +02:00
my $ tag = $ globals { MACLIST_LOG_TAG } ;
2009-02-22 18:30:14 +01:00
my $ disposition = $ config { MACLIST_DISPOSITION } ;
2013-04-11 01:43:38 +02:00
my $ audit = ( $ disposition =~ s/^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 ) {
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , s = > '0.0.0.0' , d = > '255.255.255.255' , p = > 'udp --dport 67:68'
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
#
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , s = > 'ff80::/10' ;
add_ijump $ chainref , j = > 'RETURN' , d = > 'ff80::/10' ;
2009-02-22 18:30:14 +01:00
#
# Accept Multicast
#
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , d = > IPv6_MULTICAST ;
2009-02-22 18:30:14 +01:00
}
if ( $ ttl ) {
my $ chain1ref = new_chain $ table , macrecent_target $ interface ;
my $ chain = $ chainref - > { name } ;
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , recent = > "--rcheck --seconds $ttl --name $chain" ;
2011-07-18 00:12:58 +02:00
add_ijump $ chainref , j = > $ chain1ref ;
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , recent = > "--update --name $chain" ;
add_irule $ chainref , recent = > "--set --name $chain" ;
2009-02-22 18:30:14 +01:00
}
}
2012-12-23 00:47:03 +01:00
if ( my $ fn = open_file 'maclist' , 1 , 1 ) {
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
2012-04-14 17:04:28 +02:00
while ( read_a_line ( NORMAL_READ ) ) {
2009-02-22 18:30:14 +01:00
2013-12-14 22:35:01 +01:00
my ( $ original_disposition , $ interface , $ mac , $ addresses ) =
split_line1 ( 'maclist file' ,
{ disposition = > 0 , interface = > 1 , mac = > 2 , addresses = > 3 } ) ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
my ( $ disposition , $ level , $ remainder ) = split ( /:/ , $ original_disposition , 3 ) ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
fatal_error "Invalid DISPOSITION ($original_disposition)" if defined $ remainder || ! $ disposition ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
my $ targetref = $ maclist_targets { $ disposition } ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01: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
2012-12-24 18:31:20 +01:00
my $ chainref = $ chain_table { $ table } { ( $ ttl ? macrecent_target $ interface : mac_chain $ interface ) } ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
$ mac = '' unless $ mac && ( $ mac ne '-' ) ;
$ addresses = '' unless defined $ addresses && ( $ addresses ne '-' ) ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
fatal_error "You must specify a MAC address or an IP address" unless $ mac || $ addresses ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
$ mac = do_mac $ mac if $ mac ;
2012-04-24 23:52:57 +02:00
2012-12-24 18:31:20 +01: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}"
2011-06-12 01:14:31 +02:00
if supplied $ level ;
2011-05-23 02:42:50 +02:00
2011-08-13 18:56:14 +02:00
add_ijump ( $ chainref , j = > 'AUDIT' , targetopts = > '--type ' . lc $ disposition ) if $ audit && $ disposition ne 'ACCEPT' ;
2012-12-24 18:31:20 +01:00
add_jump ( $ chainref , $ targetref - > { target } , 0 , "${mac}${source}" ) ;
2009-02-22 18:30:14 +01:00
}
2012-12-24 18:31:20 +01:00
} else {
log_rule_limit $ level , $ chainref , mac_chain ( $ interface ) , $ disposition , '' , '' , 'add' , $ mac
if supplied $ level ;
2009-02-22 18:30:14 +01:00
2012-12-24 18:31:20 +01:00
add_ijump ( $ chainref , j = > 'AUDIT' , targetopts = > '--type ' . lc $ disposition ) if $ audit && $ disposition ne 'ACCEPT' ;
add_jump ( $ chainref , $ targetref - > { target } , 0 , "$mac" ) ;
2010-09-28 19:48:44 +02:00
}
2012-12-24 18:31:20 +01:00
progress_message " Maclist entry \"$currentline\" $done" ;
2009-02-22 18:30:14 +01:00
}
2010-09-28 19:48:44 +02:00
}
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 ] ;
2014-09-11 19:17:01 +02:00
my @ policy = $ ipsec && have_ipsec ? ( policy = > "--pol $ipsec --dir in" ) : ( ) ;
2011-07-18 00:12:58 +02:00
my @ source = imatch_source_net $ hostref - > [ 2 ] ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > [ 5 ] ;
2009-02-22 18:30:14 +01:00
2012-08-08 16:23:20 +02:00
my @ state = have_capability ( 'RAW_TABLE' ) ? state_imatch 'NEW,UNTRACKED' : state_imatch 'NEW' ;
2009-02-22 18:30:14 +01:00
if ( $ table eq 'filter' ) {
my $ chainref = source_exclusion ( $ hostref - > [ 3 ] , $ filter_table - > { mac_chain $ interface } ) ;
2011-12-29 23:52:07 +01:00
for my $ chain ( option_chains $ interface ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended $ filter_table - > { $ chain } , j = > $ chainref , $ origin , @ source , @ state , @ policy ;
2009-02-22 18:30:14 +01:00
}
} else {
my $ chainref = source_exclusion ( $ hostref - > [ 3 ] , $ mangle_table - > { mac_chain $ interface } ) ;
2016-01-23 21:31:53 +01:00
add_ijump_extended $ mangle_table - > { PREROUTING } , j = > $ chainref , $ origin , imatch_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
#
2013-04-09 18:37:12 +02:00
ensure_audit_chain ( $ target , $ disposition , undef , $ table ) if $ audit ;
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' ) ) {
2011-07-16 18:41:53 +02:00
add_commands ( $ chainref , "for address in $variable; do" ) ;
incr_cmd_level ( $ chainref ) ;
2011-07-20 16:30:49 +02:00
add_ijump ( $ chainref , j = > 'RETURN' , s = > '$address' , addrtype = > '--dst-type BROADCAST' ) ;
add_ijump ( $ chainref , j = > 'RETURN' , s = > '$address' , d = > '224.0.0.0/4' ) ;
2011-07-16 18:41:53 +02:00
decr_cmd_level ( $ chainref ) ;
add_commands ( $ chainref , 'done' ) ;
2009-02-22 18:30:14 +01:00
} else {
my $ bridge = source_port_to_bridge ( $ interface ) ;
my $ bridgeref = find_interface ( $ bridge ) ;
add_commands ( $ chainref ,
"for address in $variable; do" ) ;
2011-07-17 01:31:29 +02:00
incr_cmd_level ( $ chainref ) ;
2009-02-22 18:30:14 +01:00
if ( $ bridgeref - > { broadcasts } ) {
for my $ address ( @ { $ bridgeref - > { broadcasts } } , '255.255.255.255' ) {
2011-07-20 16:30:49 +02:00
add_ijump ( $ chainref , j = > 'RETURN' , s = > '$address' , d = > $ address ) ;
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 ,
2011-07-17 01:31:29 +02:00
" for address1 in $variable1; do" ) ;
incr_cmd_level ( $ chainref ) ;
2011-07-20 16:30:49 +02:00
add_ijump ( $ chainref , j = > 'RETURN' , s = > '$address' , d = > '$address1' ) ;
2011-07-17 01:31:29 +02:00
decr_cmd_level ( $ chainref ) ;
add_commands ( $ chainref , 'done' ) ;
2009-02-22 18:30:14 +01:00
}
2011-07-20 16:30:49 +02:00
add_ijump ( $ chainref , j = > 'RETURN' , s = > '$address' , d = > '224.0.0.0/4' ) ;
2011-07-17 01:31:29 +02:00
decr_cmd_level ( $ chainref ) ;
add_commands ( $ chainref , 'done' ) ;
2009-02-22 18:30:14 +01:00
}
}
}
run_user_exit2 ( 'maclog' , $ chainref ) ;
2016-01-27 23:24:56 +01:00
log_irule_limit $ level , $ chainref , $ chain , $ disposition , [] , $ tag , 'add' , '' if $ level ne '' ;
2011-07-18 00:12:58 +02:00
add_ijump $ chainref , j = > $ target ;
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
#
2016-01-23 21:31:53 +01:00
sub generate_dest_rules ( $$$$;@ ) {
my ( $ chainref , $ chain , $ z2 , $ origin , @ matches ) = @ _ ;
2010-07-01 05:35:46 +02:00
my $ z2ref = find_zone ( $ z2 ) ;
my $ type2 = $ z2ref - > { type } ;
2011-11-17 18:23:39 +01:00
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 ) ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > { origin } ;
2010-07-09 02:11:27 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref ,
j = > $ exclusion ,
$ origin ,
imatch_dest_net ( $ net ) ,
@ matches ) ;
2010-07-01 05:35:46 +02:00
}
}
} else {
2016-01-23 21:31:53 +01:00
add_ijump_extended ( $ chainref , j = > $ chain , $ origin , @ matches ) ;
2010-07-01 05:35:46 +02:00
}
}
#
2010-07-09 02:45:18 +02:00
# Generate rules for one vserver source zone
2010-07-01 05:35:46 +02:00
#
2011-07-18 16:24:21 +02:00
sub generate_source_rules ( $$$;@ ) {
my ( $ outchainref , $ z1 , $ z2 , @ matches ) = @ _ ;
2010-07-01 05:35:46 +02:00
my $ chain = rules_target ( $ z1 , $ z2 ) ;
2010-09-27 20:16:18 +02:00
2013-04-11 18:35:27 +02:00
if ( $ chain && $ chain ne 'NONE' ) {
2010-07-01 05:35:46 +02:00
#
# Not a CONTINUE policy with no rules
#
2010-07-09 02:11:27 +02:00
for my $ hostref ( @ { defined_zone ( $ z1 ) - > { hosts } { ip } { '%vserver%' } } ) {
2011-07-18 16:24:21 +02:00
my @ ipsec_match = match_ipsec_in $ z1 , $ hostref ;
2010-07-09 02:11:27 +02:00
my $ exclusion = source_exclusion ( $ hostref - > { exclusions } , $ chain ) ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > { origin } ;
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 ,
2016-01-23 21:31:53 +01:00
$ origin ,
2011-07-18 16:24:21 +02:00
imatch_source_net ( $ net ) ,
@ matches ,
@ ipsec_match
2010-07-09 02:11:27 +02:00
) ;
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 () {
2013-05-26 23:06:51 +02:00
my @ zones = ( vserver_zones , firewall_zone ) ;
my $ natout = $ nat_table - > { OUTPUT } ;
my $ rawout = $ raw_table - > { OUTPUT } ;
my $ rulenum = 0 ;
my $ loopback = loopback_zones ;
2015-01-03 18:22:40 +01:00
my $ loref = known_interface ( loopback_interface ) ;
2010-07-01 05:35:46 +02:00
2013-06-10 21:36:18 +02:00
my $ unmanaged ;
2010-07-01 05:35:46 +02:00
my $ outchainref ;
2011-07-18 16:24:21 +02:00
my @ rule ;
2010-07-01 05:35:46 +02:00
if ( @ zones > 1 ) {
2012-06-10 02:21:59 +02:00
#
# We have a vserver zone -- route output through a separate chain
#
2010-07-01 05:35:46 +02:00
$ outchainref = new_standard_chain 'loopback' ;
2015-01-04 18:46:39 +01:00
if ( have_capability 'IFACE_MATCH' ) {
add_ijump $ filter_table - > { OUTPUT } , j = > $ outchainref , iface = > '--dev-out --loopback' ;
} else {
add_ijump $ filter_table - > { OUTPUT } , j = > $ outchainref , o = > loopback_interface ;
}
2010-07-01 05:35:46 +02:00
} else {
2012-06-10 02:21:59 +02:00
#
# Only the firewall -- just use the OUTPUT chain
#
2013-06-10 21:36:18 +02:00
if ( $ unmanaged = $ loref && $ loref - > { options } { unmanaged } ) {
2015-01-04 18:46:39 +01:00
if ( have_capability 'IFACE_MATCH' ) {
add_ijump ( $ filter_table - > { OUTPUT } , j = > 'ACCEPT' , iface = > '--dev-out --loopback' ) ;
} else {
add_ijump ( $ filter_table - > { OUTPUT } , j = > 'ACCEPT' , o = > loopback_interface ) ;
}
2013-06-10 21:36:18 +02:00
} else {
$ outchainref = $ filter_table - > { OUTPUT } ;
2015-01-04 18:46:39 +01:00
if ( have_capability 'IFACE_MATCH' ) {
@ rule = ( iface = > '--dev-out --loopback' ) ;
} else {
@ rule = ( o = > loopback_interface ) ;
}
2013-06-10 21:36:18 +02:00
}
2010-07-01 05:35:46 +02:00
}
for my $ z1 ( @ zones ) {
my $ z1ref = find_zone ( $ z1 ) ;
my $ type1 = $ z1ref - > { type } ;
my $ natref = $ nat_table - > { dnat_chain $ z1 } ;
2012-08-07 23:51:58 +02:00
my $ notrackref = $ raw_table - > { notrack_chain ( $ z1 ) } ;
2012-06-10 02:21:59 +02:00
#
# Add jumps in the 'output' chain to the rules chains
#
2010-07-01 05:35:46 +02:00
if ( $ type1 == FIREWALL ) {
for my $ z2 ( @ zones ) {
2013-06-10 21:36:18 +02:00
next if $ z1 eq $ z2 && ( $ loopback || $ unmanaged ) ;
2013-05-22 18:19:34 +02:00
2010-07-01 05:35:46 +02:00
my $ chain = rules_target ( $ z1 , $ z2 ) ;
2016-01-23 21:31:53 +01:00
generate_dest_rules ( $ outchainref , $ chain , $ z2 , '' , @ rule ) if $ chain ;
2010-07-01 05:35:46 +02:00
}
2012-08-07 23:51:58 +02:00
#
# Handle conntrack
#
if ( $ notrackref ) {
add_ijump $ rawout , j = > $ notrackref if $ notrackref - > { referenced } ;
}
2010-07-01 05:35:46 +02:00
} else {
for my $ z2 ( @ zones ) {
2011-07-18 16:24:21 +02:00
generate_source_rules ( $ outchainref , $ z1 , $ z2 , @ rule ) ;
2010-07-01 05:35:46 +02:00
}
2012-08-07 23:51:58 +02:00
#
# Handle conntrack rules
#
if ( $ notrackref - > { referenced } ) {
2015-07-13 00:00:41 +02:00
for my $ hostref ( sort { $ a - > { type } cmp $ b - > { type } } @ { defined_zone ( $ z1 ) - > { hosts } { ip } { '%vserver%' } } ) {
2012-08-07 23:51:58 +02:00
my $ exclusion = source_exclusion ( $ hostref - > { exclusions } , $ notrackref ) ;
my @ ipsec_match = match_ipsec_in $ z1 , $ hostref ;
for my $ net ( @ { $ hostref - > { hosts } } ) {
2012-11-21 23:20:30 +01:00
insert_ijump ( $ rawout ,
j = > $ exclusion ,
$ rawout - > { insert } + + ,
imatch_source_net $ net ,
@ ipsec_match ) ;
2012-08-07 23:51:58 +02:00
}
}
}
2010-07-01 05:35:46 +02:00
}
if ( $ natref && $ natref - > { referenced } ) {
2012-06-10 02:21:59 +02:00
#
# There are DNAT rules with this zone as the source -- add jumps from the nat OUTPUT chain
#
2010-07-01 05:35:46 +02:00
my $ source_hosts_ref = defined_zone ( $ z1 ) - > { hosts } ;
2015-07-13 00:00:41 +02:00
for my $ typeref ( sort { $ a - > { type } cmp $ b - > { type } } values % { $ source_hosts_ref } ) {
for my $ hostref ( sort { $ a - > { type } cmp $ b - > { type } } @ { $ typeref - > { '%vserver%' } } ) {
2010-07-01 05:35:46 +02:00
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 } } ) {
2012-04-24 23:52:57 +02:00
insert_ijump ( $ natout ,
2011-07-18 16:24:21 +02:00
j = > $ exclusion ,
$ rulenum + + ,
imatch_source_net ( $ net , 0 , ) ) ;
2010-07-01 05:35:46 +02:00
}
2010-09-27 20:16:18 +02:00
}
2010-07-01 05:35:46 +02:00
}
}
}
}
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 ;
2015-07-12 19:54:48 +02:00
my @ interfaces = sort grep $ _ ne '%vserver%' , @ _ ;
2012-07-15 19:05:32 +02:00
my $ dummy ;
2015-01-03 18:22:40 +01:00
my $ lo_jump_added = interface_zone ( loopback_interface ) && ! get_interface_option ( loopback_interface , 'destonly' ) ;
2009-02-22 18:30:14 +01:00
#
# Add Nat jumps
#
for my $ interface ( @ _ ) {
2016-02-20 18:24:06 +01:00
addnatjump $ globals { POSTROUTING } , snat_chain ( $ interface ) , imatch_dest_dev ( $ interface ) ;
2009-02-22 18:30:14 +01:00
}
2016-02-20 18:24:06 +01:00
addnatjump ( 'POSTROUTING' , 'SHOREWALL' ) if $ config { DOCKER } ;
2012-02-01 19:25:26 +01:00
for my $ interface ( @ interfaces ) {
2011-07-19 20:58:10 +02:00
addnatjump 'PREROUTING' , input_chain ( $ interface ) , imatch_source_dev ( $ interface ) ;
2016-02-20 18:24:06 +01:00
addnatjump $ globals { POSTROUTING } , output_chain ( $ interface ) , imatch_dest_dev ( $ interface ) ;
addnatjump $ globals { POSTROUTING } , masq_chain ( $ interface ) , imatch_dest_dev ( $ interface ) ;
2012-04-24 23:52:57 +02:00
2011-08-14 21:01:17 +02:00
if ( have_capability 'RAWPOST_TABLE' ) {
insert_ijump ( $ rawpost_table - > { POSTROUTING } , j = > postrouting_chain ( $ interface ) , 0 , imatch_dest_dev ( $ interface ) ) if $ rawpost_table - > { postrouting_chain $ interface } ;
insert_ijump ( $ raw_table - > { PREROUTING } , j = > prerouting_chain ( $ interface ) , 0 , imatch_source_dev ( $ interface ) ) if $ raw_table - > { prerouting_chain $ interface } ;
insert_ijump ( $ raw_table - > { OUTPUT } , j = > output_chain ( $ interface ) , 0 , imatch_dest_dev ( $ interface ) ) if $ raw_table - > { output_chain $ interface } ;
}
2012-07-15 19:05:32 +02:00
add_ijump ( $ mangle_table - > { PREROUTING } , j = > 'rpfilter' , imatch_source_dev ( $ interface ) ) if interface_has_option ( $ interface , 'rpfilter' , $ dummy ) ;
2009-02-22 18:30:14 +01:00
}
#
# Add the jumps to the interface chains from filter FORWARD, INPUT, OUTPUT
#
2012-02-01 19:25:26 +01:00
for my $ interface ( @ interfaces ) {
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 ) ;
2015-01-04 18:46:39 +01:00
if ( $ interfaceref - > { physical } eq '+' && ! $ lo_jump_added + + ) {
if ( have_capability 'IFACE_MATCH' ) {
add_ijump $ filter_table - > { INPUT } , j = > 'ACCEPT' , iface = > '--dev-in --loopback' ;
} else {
add_ijump $ filter_table - > { INPUT } , j = > 'ACCEPT' , i = > loopback_interface ;
}
}
2011-11-11 16:28:35 +01:00
2011-04-03 18:56:30 +02:00
if ( $ interfaceref - > { options } { port } ) {
my $ bridge = $ interfaceref - > { bridge } ;
2012-04-30 16:48:07 +02:00
2011-07-20 16:30:49 +02:00
add_ijump ( $ filter_table - > { forward_chain $ bridge } ,
2011-07-18 00:12:58 +02:00
j = > 'ACCEPT' ,
imatch_source_dev ( $ interface , 1 ) ,
imatch_dest_dev ( $ interface , 1 )
2012-04-30 16:48:07 +02:00
) unless $ interfaceref - > { nets } ;
2011-04-03 18:56:30 +02:00
2011-07-18 16:24:21 +02:00
add_ijump ( $ filter_table - > { forward_chain $ bridge } ,
2012-04-24 23:52:57 +02:00
j = > $ forwardref ,
2011-07-18 16:24:21 +02:00
imatch_source_dev ( $ interface , 1 )
) unless $ forward_jump_added { $ interface } || ! use_forward_chain $ interface , $ forwardref ;
2011-04-03 18:56:30 +02:00
2011-07-18 16:24:21 +02:00
add_ijump ( $ filter_table - > { input_chain $ bridge } ,
j = > $ inputref ,
imatch_source_dev ( $ interface , 1 )
2011-04-03 18:56:30 +02:00
) unless $ input_jump_added { $ interface } || ! use_input_chain $ interface , $ inputref ;
unless ( $ output_jump_added { $ interface } || ! use_output_chain $ interface , $ outputref ) {
2011-07-18 16:24:21 +02:00
add_ijump ( $ filter_table - > { output_chain $ bridge } ,
j = > $ outputref ,
imatch_dest_dev ( $ interface , 1 ) )
2011-04-03 18:56:30 +02:00
unless get_interface_option ( $ interface , 'port' ) ;
}
} else {
2011-07-20 16:30:49 +02:00
add_ijump ( $ filter_table - > { FORWARD } , j = > 'ACCEPT' , imatch_source_dev ( $ interface ) , imatch_dest_dev ( $ interface ) ) unless $ interfaceref - > { nets } || ! $ interfaceref - > { options } { bridge } ;
2009-02-22 18:30:14 +01:00
2011-11-11 16:28:35 +01:00
add_ijump ( $ filter_table - > { FORWARD } , j = > $ forwardref , imatch_source_dev ( $ interface ) ) if use_forward_chain ( $ interface , $ forwardref ) && ! $ forward_jump_added { $ interface } + + ;
add_ijump ( $ filter_table - > { INPUT } , j = > $ inputref , imatch_source_dev ( $ interface ) ) if use_input_chain ( $ interface , $ inputref ) && ! $ input_jump_added { $ interface } + + ;
2010-03-11 02:25:06 +01:00
2011-11-11 16:28:35 +01:00
if ( use_output_chain $ interface , $ outputref ) {
add_ijump $ filter_table - > { OUTPUT } , j = > $ outputref , imatch_dest_dev ( $ interface ) unless get_interface_option ( $ interface , 'port' ) || $ output_jump_added { $ interface } + + ;
2011-04-03 18:56:30 +02:00
}
2009-02-22 18:30:14 +01:00
}
}
2015-01-04 18:46:39 +01:00
unless ( $ lo_jump_added + + ) {
if ( have_capability 'IFACE_MATCH' ) {
add_ijump $ filter_table - > { INPUT } , j = > 'ACCEPT' , iface = > '--dev-in --loopback' ;
} else {
add_ijump $ filter_table - > { INPUT } , j = > 'ACCEPT' , i = > loopback_interface ;
}
}
2011-11-11 16:28:35 +01:00
2010-07-01 05:35:46 +02:00
handle_loopback_traffic ;
2009-02-22 18:30:14 +01:00
}
#
2012-06-07 16:47:33 +02:00
# Do the initial matrix processing for a complex zone
2009-02-22 18:30:14 +01:00
#
2012-06-07 16:47:33 +02:00
sub handle_complex_zone ( $$ ) {
my ( $ zone , $ zoneref ) = @ _ ;
our % input_jump_added ;
our % output_jump_added ;
our % forward_jump_added ;
our % ipsec_jump_added ;
2010-12-18 05:16:09 +01:00
#
2012-06-07 16:47:33 +02:00
# Complex zone or we have more than two off-firewall zones -- Shorewall::Rules::classic_blacklist created a zone forwarding chain
2010-12-18 05:16:09 +01:00
#
2012-06-07 16:47:33 +02:00
my $ frwd_ref = $ filter_table - > { zone_forward_chain ( $ zone ) } ;
2012-04-24 23:52:57 +02:00
2012-06-07 16:47:33 +02:00
assert ( $ frwd_ref , $ zone ) ;
#
# Add Zone mark if any
#
add_ijump ( $ frwd_ref , j = > 'MARK --set-mark ' . in_hex ( $ zoneref - > { mark } ) . '/' . in_hex ( $ globals { ZONE_MASK } ) ) if $ zoneref - > { mark } ;
2010-12-18 05:16:09 +01:00
2012-06-07 16:47:33 +02:00
if ( have_ipsec ) {
#
2012-08-16 17:34:30 +02:00
# In general, policy match can only match an 'in' or an 'out' policy (but not both), so we place the
2012-06-07 16:47:33 +02:00
# '--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.
#
my $ type = $ zoneref - > { type } ;
my $ source_ref = ( $ zoneref - > { hosts } { ipsec } ) || { } ;
for my $ interface ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys %$ source_ref ) {
my $ sourcechainref = $ filter_table - > { forward_chain $ interface } ;
my @ interfacematch ;
my $ interfaceref = find_interface $ interface ;
2013-05-12 18:27:12 +02:00
next if $ interfaceref - > { options } { destonly } ;
2012-06-07 16:47:33 +02:00
if ( use_forward_chain ( $ interface , $ sourcechainref ) ) {
2012-06-10 02:21:59 +02:00
#
# Use the interface forward chain
#
2012-06-07 16:47:33 +02:00
if ( $ interfaceref - > { ports } && $ interfaceref - > { options } { bridge } ) {
2012-06-10 02:21:59 +02:00
#
# This is a bridge with ports
#
2012-06-07 16:47:33 +02:00
@ interfacematch = imatch_source_dev $ interface ;
2012-06-10 02:21:59 +02:00
#
# Copy the rules from the interface forward chain to the zone forward chain unless they have already been copied
#
2012-06-07 16:47:33 +02:00
copy_rules ( $ sourcechainref , $ frwd_ref , 1 ) unless $ ipsec_jump_added { $ zone } + + ;
2012-06-10 02:21:59 +02:00
#
# Jump directly from FORWARD to the zone forward chain
#
2012-06-07 16:47:33 +02:00
$ sourcechainref = $ filter_table - > { FORWARD } ;
} elsif ( $ interfaceref - > { options } { port } ) {
#
2012-06-10 02:21:59 +02:00
# The forwarding chain for a bridge with ports is always used -- use physdev match for this interface
2012-06-07 16:47:33 +02:00
#
add_ijump ( $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ,
j = > $ sourcechainref ,
imatch_source_dev ( $ interface , 1 ) )
unless $ forward_jump_added { $ interface } + + ;
} else {
2012-06-10 02:21:59 +02:00
#
# Add jump from FORWARD to the intrface forward chain
#
2012-06-07 16:47:33 +02:00
add_ijump $ filter_table - > { FORWARD } , j = > $ sourcechainref , imatch_source_dev ( $ interface ) unless $ forward_jump_added { $ interface } + + ;
}
} else {
if ( $ interfaceref - > { options } { port } ) {
#
2012-06-10 02:21:59 +02:00
# The forwarding chain for a bridge with ports is always used -- use physdev match
2012-06-07 16:47:33 +02:00
#
$ sourcechainref = $ filter_table - > { forward_chain $ interfaceref - > { bridge } } ;
@ interfacematch = imatch_source_dev $ interface , 1 ;
} else {
$ sourcechainref = $ filter_table - > { FORWARD } ;
@ interfacematch = imatch_source_dev $ interface ;
}
2012-06-10 02:21:59 +02:00
#
# copy any rules from the interface forward chain to the zone forward chain
#
2012-06-07 16:47:33 +02:00
move_rules ( $ filter_table - > { forward_chain $ interface } , $ frwd_ref ) ;
}
2011-05-23 02:42:50 +02:00
2012-06-07 16:47:33 +02:00
my $ arrayref = $ source_ref - > { $ interface } ;
2012-06-10 02:21:59 +02:00
#
# Now add the jumps from the source chain (interface forward or FORWARD) to the zone forward chain
#
2012-06-07 16:47:33 +02:00
for my $ hostref ( @ { $ arrayref } ) {
my @ ipsec_match = match_ipsec_in $ zone , $ hostref ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > { origin } ;
2012-06-07 16:47:33 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended (
$ sourcechainref ,
@ { $ zoneref - > { parents } } ? 'j' : 'g' = > source_exclusion ( $ hostref - > { exclusions } , $ frwd_ref ) ,
$ origin ,
@ interfacematch ,
imatch_source_net ( $ net ) ,
@ ipsec_match
) ;
2012-06-07 16:47:33 +02:00
}
}
}
}
}
#
# The passed zone 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.
#
sub handle_nested_zone ( $$ ) {
my ( $ zone , $ zoneref ) = @ _ ;
2009-02-22 18:30:14 +01:00
#
2012-06-07 16:47:33 +02:00
# Function returns this 3-tuple
2009-02-22 18:30:14 +01:00
#
2012-06-07 16:47:33 +02:00
my ( $ nested , $ parenthasnat , $ parenthasnotrack ) = ( 1 , 0 , 0 ) ;
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 ;
}
2012-04-24 23:52:57 +02:00
2012-06-07 16:47:33 +02:00
if ( $ parenthasnat || $ parenthasnotrack ) {
for my $ zone1 ( all_zones ) {
if ( $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } eq 'CONTINUE' ) {
#
# 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 {
2010-09-24 20:16:31 +02:00
#
2012-06-07 16:47:33 +02:00
# 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.
2010-09-24 20:16:31 +02:00
#
2012-06-07 16:47:33 +02:00
$ nested = 0 ;
}
2010-09-24 20:16:31 +02:00
2012-06-07 16:47:33 +02:00
( $ nested , $ parenthasnat , $ parenthasnotrack ) ;
}
#
2012-06-10 02:21:59 +02:00
# Add output jump to the passed zone:interface:hostref:net
2012-06-07 16:47:33 +02:00
#
2016-01-24 00:13:12 +01:00
sub add_output_jumps ( $$$$$$$$ ) {
my ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ isport , $ bridge , $ origin ) = @ _ ;
2012-06-07 16:47:33 +02:00
our @ vservers ;
our % output_jump_added ;
2010-09-24 20:16:31 +02:00
2015-08-07 22:46:16 +02:00
my $ chain1 = rules_target ( firewall_zone , $ zone ) ;
2012-06-08 16:40:26 +02:00
my $ chain1ref = $ filter_table - > { $ chain1 } ;
my $ nextchain = dest_exclusion ( $ exclusions , $ chain1 ) ;
my $ outputref ;
my $ interfacechainref = $ filter_table - > { output_chain $ interface } ;
my @ interfacematch ;
my $ use_output = 0 ;
my @ dest = imatch_dest_net $ net ;
my @ ipsec_out_match = match_ipsec_out $ zone , $ hostref ;
2016-04-11 19:32:26 +02:00
my @ zone_interfaces = keys % { zone_interfaces ( $ zone ) } ;
2012-06-08 16:40:26 +02:00
2016-04-11 19:32:26 +02:00
if ( @ vservers || use_output_chain ( $ interface , $ interfacechainref ) || ( @ { $ interfacechainref - > { rules } } && ! $ chain1ref ) || @ zone_interfaces > 1 ) {
2012-06-10 02:21:59 +02:00
#
# - There are vserver zones (so OUTPUT will have multiple source; or
# - We must use the interface output chain; or
# - There are rules in the interface chain and none in the rules chain
2016-04-11 19:32:26 +02:00
# - The zone has multiple interfaces
2012-06-10 02:21:59 +02:00
#
# In any of these cases use the inteface output chain
#
2012-06-08 16:40:26 +02:00
$ outputref = $ interfacechainref ;
if ( $ isport ) {
2012-06-10 02:21:59 +02:00
#
# It is a bridge port zone -- use the bridges output chain and match the physdev
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ filter_table - > { output_chain $ bridge } ,
j = > $ outputref ,
$ origin ,
imatch_dest_dev ( $ interface , 1 ) )
2012-06-08 16:40:26 +02:00
unless $ output_jump_added { $ interface } + + ;
} else {
2012-06-10 02:21:59 +02:00
#
2016-04-11 19:32:26 +02:00
# Not a bridge -- match the output interface
2012-06-10 02:21:59 +02:00
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ filter_table - > { OUTPUT } , j = > $ outputref , $ origin , imatch_dest_dev ( $ interface ) unless $ output_jump_added { $ interface } + + ;
2012-06-08 16:40:26 +02:00
}
2011-04-03 18:56:30 +02:00
2012-06-08 16:40:26 +02:00
$ use_output = 1 ;
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
unless ( lc $ net eq IPv6_LINKLOCAL ) {
2012-06-10 02:21:59 +02:00
#
# Generate output rules for the vservers
#
2012-06-08 16:40:26 +02:00
for my $ vzone ( @ vservers ) {
generate_source_rules ( $ outputref , $ vzone , $ zone , @ dest ) ;
}
}
} elsif ( $ isport ) {
2012-06-10 02:21:59 +02:00
#
# It is a bridge port zone -- use the bridges output chain and match the physdev
#
2012-06-08 16:40:26 +02:00
$ outputref = $ filter_table - > { output_chain $ bridge } ;
@ interfacematch = imatch_dest_dev $ interface , 1 ;
} else {
2012-06-10 02:21:59 +02:00
#
# Just put the jump in the OUTPUT chain
#
2012-06-08 16:40:26 +02:00
$ outputref = $ filter_table - > { OUTPUT } ;
@ interfacematch = imatch_dest_dev $ interface ;
}
2012-06-10 02:21:59 +02:00
#
# Add the jump
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ outputref , j = > $ nextchain , $ origin , @ interfacematch , @ dest , @ ipsec_out_match ;
2012-06-10 02:21:59 +02:00
#
# Add jump for broadcast
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ outputref , j = > $ nextchain , get_interface_origin ( $ interface ) , @ interfacematch , d = > '255.255.255.255' , @ ipsec_out_match )
2012-06-08 16:40:26 +02:00
if $ family == F_IPV4 && $ hostref - > { options } { broadcast } ;
2012-06-10 02:21:59 +02:00
#
# Move the rules from the interface output chain if we didn't use it
#
2012-06-08 16:40:26 +02:00
move_rules ( $ interfacechainref , $ chain1ref ) unless $ use_output ;
}
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
#
# Add prerouting jumps from the passed zone:interface:hostref:net
#
2016-01-24 00:13:12 +01:00
sub add_prerouting_jumps ( $$$$$$$$$ ) {
my ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ nested , $ parenthasnat , $ parenthasnotrack , $ origin ) = @ _ ;
2012-06-07 16:47:33 +02:00
2012-06-08 16:40:26 +02:00
my $ dnatref = $ nat_table - > { dnat_chain ( $ zone ) } ;
my $ preroutingref = $ nat_table - > { PREROUTING } ;
2012-11-21 23:20:30 +01:00
my $ rawref = $ raw_table - > { PREROUTING } ;
2012-06-08 16:40:26 +02:00
my $ notrackref = ensure_chain 'raw' , notrack_chain ( $ zone ) ;
my @ ipsec_in_match = match_ipsec_in $ zone , $ hostref ;
2012-06-07 16:47:33 +02:00
2012-06-08 16:40:26 +02:00
my @ source = imatch_source_net $ net ;
2012-06-07 16:47:33 +02:00
2012-06-08 16:40:26 +02:00
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
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ preroutingref ,
j = > source_exclusion ( $ exclusions , $ dnatref ) ,
$ origin ,
imatch_source_dev ( $ interface ) ,
@ source ,
@ ipsec_in_match ) ;
2012-06-07 16:47:33 +02:00
2012-06-08 16:40:26 +02:00
check_optimization ( $ dnatref ) if @ source ;
}
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02: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
#
2012-11-21 23:20:30 +01:00
insert_ijump $ rawref , j = > source_exclusion ( $ exclusions , $ notrackref ) , $ rawref - > { insert } + + , imatch_source_dev ( $ interface ) , @ source , @ ipsec_in_match ;
2012-06-08 16:40:26 +02: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 ) {
2012-11-21 23:49:21 +01:00
if ( $ parenthasnat ) {
2016-01-24 00:13:12 +01:00
add_ijump_extended $ preroutingref , j = > 'RETURN' , $ origin , imatch_source_dev ( $ interface ) , @ source , @ ipsec_in_match ;
2012-11-21 23:49:21 +01:00
}
if ( $ parenthasnotrack ) {
my $ rawref = $ raw_table - > { PREROUTING } ;
insert_ijump $ rawref , j = > 'RETURN' , $ rawref - > { insert } + + , imatch_source_dev ( $ interface ) , @ source , @ ipsec_in_match ;
}
2012-06-08 16:40:26 +02:00
}
}
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
#
2012-06-10 02:21:59 +02:00
# Add input jump from the passed zone:interface:hostref:net
2012-06-08 16:40:26 +02:00
#
2016-01-24 00:13:12 +01:00
sub add_input_jumps ( $$$$$$$$$ ) {
my ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ frwd_ref , $ isport , $ bridge , $ origin ) = @ _ ;
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
our @ vservers ;
our % input_jump_added ;
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
my $ chain2 = rules_target $ zone , firewall_zone ;
my $ chain2ref = $ filter_table - > { $ chain2 } ;
my $ inputchainref ;
my $ interfacechainref = $ filter_table - > { input_chain $ interface } ;
my @ interfacematch ;
my $ use_input ;
my @ source = imatch_source_net $ net ;
my @ ipsec_in_match = match_ipsec_in $ zone , $ hostref ;
if ( @ vservers || use_input_chain ( $ interface , $ interfacechainref ) || ! $ chain2 || ( @ { $ interfacechainref - > { rules } } && ! $ chain2ref ) ) {
2012-06-10 02:21:59 +02:00
#
# - There are vserver zones (so INPUT will have multiple destinations; or
# - We must use the interface input chain; or
# - The zone->firewall policy is CONTINUE; or
# - There are rules in the interface chain and none in the rules chain
#
# In any of these cases use the inteface input chain
#
2012-06-08 16:40:26 +02:00
$ inputchainref = $ interfacechainref ;
if ( $ isport ) {
2012-06-10 02:21:59 +02:00
#
# It is a bridge port zone -- use the bridges input chain and match the physdev
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ filter_table - > { input_chain $ bridge } ,
j = > $ inputchainref ,
$ origin ,
imatch_source_dev ( $ interface , 1 ) )
2012-06-08 16:40:26 +02:00
unless $ input_jump_added { $ interface } + + ;
} else {
2012-06-10 02:21:59 +02:00
#
# Not a bridge -- match the input interface
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ filter_table - > { INPUT } , j = > $ inputchainref , $ origin , imatch_source_dev ( $ interface ) unless $ input_jump_added { $ interface } + + ;
2012-06-08 16:40:26 +02:00
}
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
$ use_input = 1 ;
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
unless ( lc $ net eq IPv6_LINKLOCAL ) {
2012-06-10 02:21:59 +02:00
#
# Generate input rules for the vservers
#
2012-06-08 16:40:26 +02:00
for my $ vzone ( @ vservers ) {
my $ target = rules_target ( $ zone , $ vzone ) ;
2016-01-24 00:13:12 +01:00
generate_dest_rules ( $ inputchainref , $ target , $ vzone , $ origin , @ source , @ ipsec_in_match ) if $ target ;
2012-06-08 16:40:26 +02:00
}
}
} elsif ( $ isport ) {
2012-06-10 02:21:59 +02:00
#
# It is a bridge port zone -- use the bridges input chain and match the physdev
#
2012-06-08 16:40:26 +02:00
$ inputchainref = $ filter_table - > { input_chain $ bridge } ;
@ interfacematch = imatch_source_dev $ interface , 1 ;
} else {
2012-06-10 02:21:59 +02:00
#
# Just put the jump in the INPUT chain
#
2012-06-08 16:40:26 +02:00
$ inputchainref = $ filter_table - > { INPUT } ;
@ interfacematch = imatch_source_dev $ interface ;
}
2009-02-22 18:30:14 +01:00
2012-06-08 16:40:26 +02:00
if ( $ chain2 ) {
2012-06-10 02:21:59 +02:00
#
# Add the jump from the input chain to the rules chain
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ inputchainref , j = > source_exclusion ( $ exclusions , $ chain2 ) , $ origin , @ interfacematch , @ source , @ ipsec_in_match ;
2012-06-08 16:40:26 +02:00
move_rules ( $ interfacechainref , $ chain2ref ) unless $ use_input ;
}
2012-06-10 02:21:59 +02:00
}
2009-02-22 18:30:14 +01:00
2012-06-10 02:21:59 +02:00
#
# This function is called when there is forwarding and this net isn't IPSEC protected. It adds the jump for this net to the zone forwarding chain.
#
2016-01-24 00:13:12 +01:00
sub add_forward_jump ( $$$$$$$$$ ) {
my ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ frwd_ref , $ isport , $ bridge , $ origin ) = @ _ ;
2009-02-22 18:30:14 +01:00
2012-06-10 02:21:59 +02:00
our % forward_jump_added ;
2012-06-08 16:40:26 +02:00
2012-06-10 02:21:59 +02:00
my @ source = imatch_source_net $ net ;
my @ ipsec_in_match = match_ipsec_in $ zone , $ hostref ;
2012-06-08 16:40:26 +02:00
2012-06-10 02:21:59 +02:00
my $ ref = source_exclusion ( $ exclusions , $ frwd_ref ) ;
my $ forwardref = $ filter_table - > { forward_chain $ interface } ;
if ( use_forward_chain $ interface , $ forwardref ) {
#
# We must use the interface forwarding chain -- add the jump from the interface forward chain to the zone forward chain.
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ forwardref , j = > $ ref , $ origin , @ source , @ ipsec_in_match ;
2012-06-10 02:21:59 +02:00
if ( $ isport ) {
#
# It is a bridge port zone -- use the bridges input chain and match the physdev
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ filter_table - > { forward_chain $ bridge } ,
j = > $ forwardref ,
$ origin ,
imatch_source_dev ( $ interface , 1 ) )
2012-06-10 02:21:59 +02:00
unless $ forward_jump_added { $ interface } + + ;
} else {
#
# Not a bridge -- match the input interface
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ filter_table - > { FORWARD } , j = > $ forwardref , $ origin , imatch_source_dev ( $ interface ) unless $ forward_jump_added { $ interface } + + ;
2012-06-10 02:21:59 +02:00
}
} else {
if ( $ isport ) {
#
# It is a bridge port zone -- use the bridges input chain and match the physdev
#
2016-01-24 00:13:12 +01:00
add_ijump_extended ( $ filter_table - > { forward_chain $ bridge } ,
j = > $ ref ,
$ origin ,
imatch_source_dev ( $ interface , 1 ) ,
@ source ,
@ ipsec_in_match ) ;
2012-06-10 02:21:59 +02:00
} else {
#
# Not a bridge -- match the input interface
#
2016-01-24 00:13:12 +01:00
add_ijump_extended $ filter_table - > { FORWARD } , j = > $ ref , $ origin , imatch_source_dev ( $ interface ) , @ source , @ ipsec_in_match ;
2012-06-08 16:40:26 +02:00
}
2012-06-10 02:21:59 +02:00
move_rules ( $ forwardref , $ frwd_ref ) ;
2012-06-08 16:40:26 +02:00
}
2012-06-07 16:47:33 +02:00
}
2010-02-01 23:24:07 +01:00
2012-06-07 16:47:33 +02:00
#
# Generate the list of destination zones from the passed source zone when optimization level 1 is selected
#
2012-06-10 02:21:59 +02:00
# - Drop zones where the policy to that zone is 'NONE'
# - Drop this zone if it has only one interface without 'routeback'
# - Drop BPORT zones that are not on the same bridge
# - Eliminate duplicate zones that have the same '2all' (-all) rules chain.
#
2012-06-07 16:47:33 +02:00
sub optimize1_zones ( $$@ ) {
my $ zone = shift ;
my $ zoneref = shift ;
my $ last_chain = '' ;
my @ dest_zones ;
my @ temp_zones ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
for my $ zone1 ( @ _ ) {
my $ zone1ref = find_zone ( $ zone1 ) ;
my $ policy = $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } ;
2012-06-10 02:21:59 +02:00
2012-06-07 16:47:33 +02:00
next if $ policy eq 'NONE' ;
2012-04-24 23:52:57 +02:00
2012-06-07 16:47:33 +02:00
my $ chain = rules_target $ zone , $ zone1 ;
2011-04-03 18:56:30 +02:00
2012-06-07 16:47:33 +02:00
next unless $ chain ;
2010-07-01 05:35:46 +02:00
2012-06-07 16:47:33 +02:00
if ( $ zone eq $ zone1 ) {
next if ( scalar ( keys ( % { $ zoneref - > { interfaces } } ) ) < 2 ) && ! $ zoneref - > { options } { in_out } { routeback } ;
}
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
if ( $ zone1ref - > { type } & BPORT ) {
next unless $ zoneref - > { bridge } eq $ zone1ref - > { bridge } ;
}
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
if ( $ chain =~ /(2all|-all)$/ ) {
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 ) ;
2009-02-22 18:30:14 +01:00
}
2012-06-07 16:47:33 +02:00
} else {
push @ dest_zones , @ temp_zones , $ zone1 ;
@ temp_zones = ( ) ;
$ last_chain = '' ;
2009-02-22 18:30:14 +01:00
}
2012-06-07 16:47:33 +02:00
}
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
if ( $ last_chain && @ temp_zones == 1 ) {
push @ dest_zones , @ temp_zones ;
$ last_chain = '' ;
}
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
( $ last_chain , @ dest_zones ) ;
}
# Generate the rules matrix.
#
# Stealing a comment from the Burroughs B6700 MCP Operating System source, "generate_matrix makes a sow's ear out of a silk purse".
#
# 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.
#
2012-11-21 23:49:21 +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, raw-table and
2012-06-07 16:47:33 +02:00
# nat-table rules.
#
sub generate_matrix () {
2013-06-10 21:36:18 +02:00
my @ interfaces = ( managed_interfaces ) ;
2015-06-02 00:55:06 +02:00
my @ zones = off_firewall_zones ;
our @ vservers = vserver_zones ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
my $ interface_jumps_added = 0 ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
our % input_jump_added = ( ) ;
our % output_jump_added = ( ) ;
our % forward_jump_added = ( ) ;
our % ipsec_jump_added = ( ) ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
progress_message2 'Generating Rule Matrix...' ;
progress_message ' Handling complex zones...' ;
#
# Special processing for configurations with more than 2 off-firewall zones or with other special considerations like IPSEC.
2012-06-09 15:20:40 +02:00
# Don't be tempted to move this logic into the zone loop below -- it won't work.
2012-06-07 16:47:33 +02:00
#
for my $ zone ( @ zones ) {
my $ zoneref = find_zone ( $ zone ) ;
2012-06-08 17:29:36 +02:00
if ( @ zones > 2 || $ zoneref - > { complex } ) {
handle_complex_zone ( $ zone , $ zoneref ) ;
} else {
new_standard_chain zone_forward_chain ( $ zone ) if @ zones > 1 ;
}
2012-06-07 16:47:33 +02:00
}
#
# Main source-zone matrix-generation loop
#
progress_message ' Entering main matrix-generation loop...' ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
for my $ zone ( @ zones ) {
my $ zoneref = find_zone ( $ zone ) ;
my $ source_hosts_ref = $ zoneref - > { hosts } ;
my $ frwd_ref = $ filter_table - > { zone_forward_chain $ zone } ;
my $ nested = @ { $ zoneref - > { parents } } ;
my $ parenthasnat = 0 ;
my $ parenthasnotrack = 0 ;
2013-05-26 23:06:51 +02:00
my $ type = $ zoneref - > { type } ;
2012-06-07 22:44:03 +02:00
#
# Create the zone's dnat chain
#
ensure_chain 'nat' , dnat_chain ( $ zone ) ;
2009-02-22 18:30:14 +01:00
2012-06-07 16:47:33 +02:00
( $ nested , $ parenthasnat , $ parenthasnotrack ) = handle_nested_zone ( $ zone , $ zoneref ) if $ nested ;
#
# Take care of PREROUTING, INPUT and OUTPUT jumps
#
2015-07-13 00:00:41 +02:00
for my $ type ( sort keys %$ source_hosts_ref ) {
my $ typeref = $ source_hosts_ref - > { $ type } ;
2012-06-07 16:47:33 +02:00
for my $ interface ( sort { interface_number ( $ a ) <=> interface_number ( $ b ) } keys %$ typeref ) {
if ( get_physical ( $ interface ) eq '+' ) {
#
# Insert the interface-specific jumps before this one which is not interface-specific
#
add_interface_jumps ( @ interfaces ) unless $ interface_jumps_added + + ;
2009-02-22 18:30:14 +01:00
}
2012-06-08 16:40:26 +02:00
my $ interfaceref = find_interface $ interface ;
my $ isport = $ interfaceref - > { options } { port } ;
my $ bridge = $ interfaceref - > { bridge } ;
for my $ hostref ( @ { $ typeref - > { $ interface } } ) {
my $ exclusions = $ hostref - > { exclusions } ;
2016-01-24 00:13:12 +01:00
my $ origin = $ hostref - > { origin } ;
2012-06-08 16:40:26 +02:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
#
# OUTPUT
#
if ( rules_target ( firewall_zone , $ zone ) && ! ( zone_type ( $ zone ) & BPORT ) ) {
#
# Policy from the firewall to this zone is not 'CONTINUE' and this isn't a bport zone
#
2016-01-24 00:13:12 +01:00
add_output_jumps ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ isport , $ bridge , $ origin ) ;
2012-06-08 16:40:26 +02:00
}
clearrule ;
unless ( $ hostref - > { options } { destonly } ) {
#
# PREROUTING
#
2016-01-24 00:13:12 +01:00
add_prerouting_jumps ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ nested , $ parenthasnat , $ parenthasnotrack , $ origin ) ;
2012-06-08 16:40:26 +02:00
#
# INPUT
#
2016-01-24 00:13:12 +01:00
add_input_jumps ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ frwd_ref , $ isport , $ bridge , $ origin ) ;
2012-06-10 02:21:59 +02:00
#
# FORWARDING Jump for non-IPSEC host group
#
2016-01-24 00:13:12 +01:00
add_forward_jump ( $ zone , $ interface , $ hostref , $ net , $ exclusions , $ frwd_ref , $ isport , $ bridge , $ origin ) if $ frwd_ref && $ hostref - > { ipsec } ne 'ipsec' ;
2012-06-08 16:40:26 +02:00
}
} # Subnet Loop
} # Hostref Loop
} # Interface Loop
} #Type Loop
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
if ( $ frwd_ref ) {
#
# F O R W A R D I N G
#
my @ dest_zones ;
my $ last_chain = '' ;
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
if ( $ config { OPTIMIZE } & 1 ) {
( $ last_chain , @ dest_zones ) = optimize1_zones ( $ zone , $ zoneref , @ zones ) ;
} else {
@ dest_zones = @ zones ;
}
#
# 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 ) ;
2013-05-26 23:06:51 +02:00
my $ type1 = $ zone1ref - > { type } ;
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
next if $ filter_table - > { rules_chain ( $ { zone } , $ { zone1 } ) } - > { policy } eq 'NONE' ;
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
my $ chain = rules_target $ zone , $ zone1 ;
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
next unless $ chain ; # CONTINUE policy with no rules
my $ num_ifaces = 0 ;
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
if ( $ zone eq $ zone1 ) {
next if ( $ num_ifaces = scalar ( keys ( % { $ zoneref - > { interfaces } } ) ) ) < 2 && ! $ zoneref - > { options } { in_out } { routeback } ;
}
2009-02-22 18:30:14 +01:00
2013-05-26 23:06:51 +02:00
if ( $ type1 & BPORT ) {
2012-06-08 17:29:36 +02:00
next unless $ zoneref - > { bridge } eq $ zone1ref - > { bridge } ;
}
2009-02-22 18:30:14 +01:00
2012-06-08 17:29:36 +02:00
my $ chainref = $ filter_table - > { $ chain } ; #Will be null if $chain is a Netfilter Built-in target like ACCEPT
2015-07-13 00:00:41 +02:00
for my $ type ( sort keys % { $ zone1ref - > { hosts } } ) {
my $ typeref = $ zone1ref - > { hosts } { $ type } ;
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 } } ) {
2013-05-20 00:35:20 +02:00
next if $ hostref - > { options } { sourceonly } ;
2009-02-22 18:30:14 +01:00
if ( $ zone ne $ zone1 || $ num_ifaces > 1 || $ hostref - > { options } { routeback } ) {
2011-07-18 16:24:21 +02:00
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 ) ;
2016-01-23 21:31:53 +01:00
my $ origin = $ hostref - > { origin } ;
2009-02-22 18:30:14 +01:00
for my $ net ( @ { $ hostref - > { hosts } } ) {
2016-01-23 21:31:53 +01:00
add_ijump_extended $ frwd_ref , j = > $ dest_exclusion , $ origin , imatch_dest_dev ( $ interface ) , imatch_dest_net ( $ net ) , @ ipsec_out_match ;
2009-02-22 18:30:14 +01:00
}
}
}
}
}
}
2012-06-08 17:29:36 +02: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_ijump $ frwd_ref , g = > $ last_chain if $ frwd_ref && $ last_chain ;
2012-06-09 15:20:40 +02:00
} # Forwarding required
} # Source Zone Loop
2009-02-22 18:30:14 +01:00
2010-09-26 01:07:56 +02:00
progress_message ' Finishing matrix...' ;
2012-09-27 00:46:52 +02:00
#
# Make sure that the 1:1 NAT jumps are last in PREROUTING
#
2016-02-20 18:24:06 +01:00
addnatjump 'PREROUTING' , 'nat_in' ;
addnatjump $ globals { POSTROUTING } , 'nat_out' ;
2010-09-26 01:07:56 +02:00
2009-02-22 18:30:14 +01:00
add_interface_jumps @ interfaces unless $ interface_jumps_added ;
2010-08-01 17:36:56 +02:00
unless ( $ config { COMPLETE } ) {
2013-06-10 21:36:18 +02:00
for ( unmanaged_interfaces ) {
my $ physical = get_physical $ _ ;
add_ijump ( $ filter_table - > { INPUT } , j = > 'ACCEPT' , i = > $ physical ) ;
add_ijump ( $ filter_table - > { OUTPUT } , j = > 'ACCEPT' , o = > $ physical ) ;
}
2010-08-01 17:36:56 +02:00
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 } ) {
2013-06-10 21:36:18 +02:00
my % builtins = ( mangle = > [ qw/PREROUTING INPUT FORWARD POSTROUTING/ ] ,
nat = > [ qw/PREROUTING OUTPUT POSTROUTING/ ] ,
filter = > [ qw/INPUT FORWARD OUTPUT/ ] ) ;
2016-01-26 00:49:18 +01:00
my $ origin = $ origin { LOGALLNEW } ;
2011-06-13 15:39:38 +02:00
for my $ table ( qw/mangle nat filter/ ) {
2009-02-22 18:30:14 +01:00
for my $ chain ( @ { $ builtins { $ table } } ) {
2016-01-27 23:24:56 +01:00
log_rule_limit ( $ config { LOGALLNEW } ,
$ chain_table { $ table } { $ chain } ,
$ table ,
$ chain ,
'' ,
'' ,
'insert' ,
state_match ( 'NEW' ) ,
$ origin ) ;
2009-02-22 18:30:14 +01:00
}
}
}
}
sub setup_mss ( ) {
my $ clampmss = $ config { CLAMPMSS } ;
my $ option ;
2011-07-18 00:12:58 +02:00
my @ match ;
2009-02-22 18:30:14 +01:00
my $ chainref = $ filter_table - > { FORWARD } ;
if ( $ clampmss ) {
if ( "\L$clampmss" eq 'yes' ) {
2011-08-13 18:56:14 +02:00
$ option = '--clamp-mss-to-pmtu' ;
2009-02-22 18:30:14 +01:00
} else {
2011-07-18 00:12:58 +02:00
@ match = ( tcpmss = > "--mss $clampmss:" ) if have_capability ( 'TCPMSS_MATCH' ) ;
2011-08-13 18:56:14 +02:00
$ option = "--set-mss $clampmss" ;
2009-02-22 18:30:14 +01:00
}
2011-07-18 00:12:58 +02:00
push @ match , ( 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
#
2011-07-19 20:58:10 +02:00
add_ijump $ filter_table - > { FORWARD } , j = > $ chainref , p = > 'tcp --tcp-flags SYN,RST SYN' ;
2009-02-22 18:30:14 +01:00
2011-07-18 00:12:58 +02:00
my @ in_match = ( ) ;
my @ out_match = ( ) ;
2009-02-22 18:30:14 +01:00
2010-01-25 17:13:22 +01:00
if ( have_ipsec ) {
2011-07-18 00:12:58 +02:00
@ in_match = ( policy = > '--pol none --dir in' ) ;
@ out_match = ( 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' ) ;
2011-07-18 00:12:58 +02:00
my @ mssmatch = have_capability ( 'TCPMSS_MATCH' ) ? ( tcpmss = > "--mss $mss:" ) : ( ) ;
my @ source = imatch_source_dev $ _ ;
my @ dest = imatch_dest_dev $ _ ;
2011-08-13 18:56:14 +02:00
add_ijump $ chainref , j = > 'TCPMSS' , targetopts = > "--set-mss $mss" , @ dest , p = > 'tcp --tcp-flags SYN,RST SYN' , @ mssmatch , @ out_match ;
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , @ dest if $ clampmss ;
2011-08-13 18:56:14 +02:00
add_ijump $ chainref , j = > 'TCPMSS' , targetopts = > "--set-mss $mss" , @ source , p = > 'tcp --tcp-flags SYN,RST SYN' , @ mssmatch , @ in_match ;
2011-07-20 16:30:49 +02:00
add_ijump $ chainref , j = > 'RETURN' , @ source if $ clampmss ;
2009-02-22 18:30:14 +01:00
}
}
2011-08-13 18:56:14 +02:00
add_ijump $ chainref , j = > 'TCPMSS' , targetopts = > $ option , p = > 'tcp --tcp-flags SYN,RST SYN' , @ match if $ clampmss ;
2009-02-22 18:30:14 +01:00
}
2009-03-28 20:22:15 +01:00
#
# Compile the stop_firewall() function
#
2015-08-07 22:46:16 +02:00
sub compile_stop_firewall ( $$$$ ) {
2015-08-31 23:21:41 +02:00
my ( $ test , $ export , $ have_arptables , $ convert ) = @ _ ;
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 } ;
2015-07-26 19:27:30 +02:00
emit << 'EOF' ;
2015-06-06 21:15:03 +02:00
#
# Stop/restore the firewall after an error or because of a 'stop' or 'clear' command
#
stop_firewall ( ) {
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
2015-03-06 17:13:44 +01:00
$ { IPTABLES } - save - t filter | grep '^-A dynamic' | fgrep - v - - '-j ACCEPT' > $ { VARDIR } / . dynamic
2010-09-17 03:19:16 +02:00
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
2015-03-06 17:13:44 +01:00
$ { IP6TABLES } - save - t filter | grep '^-A dynamic' | fgrep - v - - '-j ACCEPT' > $ { 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 )
2016-04-15 23:29:51 +02:00
mylogger kern . err "ERROR:$g_product start failed"
2009-03-28 20:22:15 +01:00
; ;
2015-07-26 18:59:49 +02:00
reload )
2016-04-15 23:29:51 +02:00
mylogger kern . err "ERROR:$g_product reload failed"
2009-03-28 20:22:15 +01:00
; ;
2010-01-06 17:01:06 +01:00
refresh )
2016-04-15 23:29:51 +02:00
mylogger kern . err "ERROR:$g_product refresh failed"
2009-03-28 20:22:15 +01:00
; ;
2011-08-26 01:00:27 +02:00
enable )
2016-04-15 23:29:51 +02:00
mylogger kern . err "ERROR:$g_product 'enable $g_interface' failed"
2011-08-26 01:00:27 +02:00
; ;
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
2012-08-12 17:42:53 +02:00
#
# Enable automatic helper association on kernel 3.5.0 and later
#
2013-05-26 01:31:27 +02:00
if [ $ COMMAND = clear - a - f /proc/s ys /net/ netfilter / nf_conntrack_helper ] ; then
2012-08-12 17:42:53 +02:00
echo 1 > /proc/s ys /net/ netfilter / nf_conntrack_helper
fi
2009-03-28 20:22:15 +01:00
EOF
2016-02-25 22:37:44 +01:00
if ( $ config { DOCKER } ) {
push_indent ;
emit ( 'if [ $COMMAND = stop ]; then' ) ;
push_indent ;
save_docker_rules ( $ family == F_IPV4 ? '${IPTABLES}' : '${IP6TABLES}' ) ;
pop_indent ;
emit ( "fi\n" ) ;
pop_indent ;
}
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
2011-08-03 01:51:49 +02:00
qtnoin $ IP - 4 neigh del proxy $ address dev $ external
[ - z "${haveroute}${g_noroutes}" ] && qtnoin $ 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
2011-08-03 01:51:49 +02:00
qtnoin $ IP - 6 neigh del proxy $ address dev $ external
[ - z "${haveroute}${g_noroutes}" ] && qtnoin $ IP - 6 route del $ address / 128 dev $ interface
2010-12-11 04:06:44 +01:00
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
) ;
2016-02-21 19:33:45 +01:00
#
# Insure that Docker jumps are early in the builtin chains
#
create_docker_rules if $ config { DOCKER } ;
2009-03-28 20:22:15 +01:00
2014-03-05 17:57:03 +01:00
if ( $ config { ADMINISABSENTMINDED } ) {
add_ijump $ filter_table - > { $ _ } , j = > 'ACCEPT' , state_imatch 'ESTABLISHED,RELATED' for qw/INPUT FORWARD/ ;
}
2009-03-28 20:22:15 +01:00
if ( $ family == F_IPV6 ) {
2011-07-20 16:30:49 +02:00
add_ijump $ input , j = > 'ACCEPT' , s = > IPv6_LINKLOCAL ;
add_ijump $ input , j = > 'ACCEPT' , d = > IPv6_LINKLOCAL ;
add_ijump $ input , j = > 'ACCEPT' , d = > IPv6_MULTICAST ;
2009-03-28 20:22:15 +01:00
2009-03-30 02:49:00 +02:00
unless ( $ config { ADMINISABSENTMINDED } ) {
2011-07-20 16:30:49 +02:00
add_ijump $ output , j = > 'ACCEPT' , d = > IPv6_LINKLOCAL ;
add_ijump $ output , j = > 'ACCEPT' , d = > IPv6_MULTICAST ;
2009-03-30 02:49:00 +02:00
}
2009-03-28 20:22:15 +01:00
}
2015-08-31 23:21:41 +02:00
if ( $ convert ) {
2015-08-08 21:42:32 +02:00
convert_routestopped ;
2015-08-15 00:29:52 +02:00
} elsif ( - f ( my $ fn = find_file 'routestopped' ) ) {
2015-08-31 23:21:41 +02:00
warning_message "The routestopped file is no longer supported - use '$product update' to convert $fn to an equivalent 'stoppedrules' file" ;
2015-08-08 21:42:32 +02:00
}
2015-08-07 22:46:16 +02:00
process_stoppedrules ;
2009-03-28 20:22:15 +01:00
2015-01-04 18:46:39 +01:00
if ( have_capability 'IFACE_MATCH' ) {
add_ijump $ input , j = > 'ACCEPT' , iface = > '--dev-in --loopback' ;
add_ijump $ output , j = > 'ACCEPT' , iface = > '--dev-out --loopback' unless $ config { ADMINISABSENTMINDED } ;
} else {
add_ijump $ input , j = > 'ACCEPT' , i = > loopback_interface ;
add_ijump $ output , j = > 'ACCEPT' , o = > loopback_interface 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 ) {
2011-07-20 16:30:49 +02:00
add_ijump $ input , j = > 'ACCEPT' , p = > "udp --dport $ports" , imatch_source_dev ( $ interface ) ;
add_ijump $ output , j = > 'ACCEPT' , p = > "udp --dport $ports" , imatch_dest_dev ( $ interface ) unless $ config { ADMINISABSENTMINDED } ;
2009-03-28 20:22:15 +01:00
#
# This might be a bridge
#
2011-07-20 16:30:49 +02:00
add_ijump $ forward , j = > 'ACCEPT' , p = > "udp --dport $ports" , imatch_source_dev ( $ interface ) , imatch_dest_dev ( $ interface ) ;
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 ) {
2013-01-04 18:17:57 +01:00
emit ( '$ARPTABLES -F' ,
'' ) if $ have_arptables ;
2009-03-28 20:22:15 +01:00
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
2014-09-29 03:43:11 +02:00
if ( @ ipsets || @ { $ globals { SAVED_IPSETS } } || ( $ config { SAVE_IPSETS } && have_ipset_rules ) ) {
emit ( '' ,
2014-09-29 16:08:39 +02:00
' save_ipsets ${VARDIR}/ipsets.save' ) ;
2009-03-28 20:22:15 +01:00
}
2014-09-29 03:43:11 +02:00
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"
2016-04-15 23:29:51 +02:00
mylogger 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 ;