2007-06-17 23:35:42 +02:00
#
2007-06-11 21:39:30 +02:00
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Config.pm
2007-03-15 22:55:22 +01:00
#
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
#
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
#
# Complete documentation is available at http://shorewall.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of Version 2 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
#
2007-04-19 01:43:54 +02:00
# This module is responsible for lower level configuration file handling.
# It also exports functions for generating warning and error messages.
# The get_configuration function parses the shorewall.conf, capabilities and
# modules files during compiler startup.
2007-03-15 22:55:22 +01:00
#
2007-03-14 03:44:41 +01:00
package Shorewall::Config ;
use strict ;
use warnings ;
use Shorewall::Common ;
2007-04-16 01:41:13 +02:00
use File::Basename ;
2007-03-14 03:44:41 +01:00
our @ ISA = qw( Exporter ) ;
2007-03-29 19:36:04 +02:00
our @ EXPORT = qw(
2007-04-08 16:42:26 +02:00
warning_message
2007-04-18 22:56:41 +02:00
fatal_error
2007-06-12 01:17:02 +02:00
set_shorewall_dir
2007-04-18 22:56:41 +02:00
find_file
split_line
2007-05-10 17:29:41 +02:00
split_line1
split_line2
2007-04-18 22:56:41 +02:00
open_file
close_file
push_open
pop_open
read_a_line
2007-04-24 16:53:45 +02:00
validate_level
2007-05-08 21:05:25 +02:00
qt
2007-04-18 22:56:41 +02:00
get_configuration
require_capability
report_capabilities
propagateconfig
append_file
run_user_exit
2007-05-20 18:25:53 +02:00
run_user_exit1
2007-05-20 18:37:09 +02:00
run_user_exit2
2007-04-18 22:56:41 +02:00
generate_aux_config
2007-04-18 22:53:25 +02:00
2007-04-18 22:56:41 +02:00
% config
% globals
2007-04-24 21:53:13 +02:00
% capabilities
% protocols
% services ) ;
2007-06-11 20:07:34 +02:00
2007-06-14 01:02:39 +02:00
our @ EXPORT_OK = qw( $shorewall_dir initialize ) ;
2007-03-14 03:44:41 +01:00
our @ VERSION = 1.00 ;
2007-03-24 19:11:32 +01:00
#
# Misc Globals
#
2007-06-14 01:02:39 +02:00
our % globals ;
#
# From shorewall.conf file
#
our % config ;
#
# Config options and global settings that are to be copied to object script
#
our @ propagateconfig ;
our @ propagateenv ;
#
# From parsing the capabilities file
#
our % capabilities ;
#
# /etc/protocols and /etc/services
#
our % protocols ;
our % services ;
#
# Capabilities
#
our % capdesc ;
#
# Directories to search for configuration files
#
our @ config_path ;
#
# Stash away file references here when we encounter INCLUDE
#
our @ includestack ;
#
# Allow nested opens
#
our @ openstack ;
our $ currentfile ; # File handle reference
our $ currentfilename ; # File NAME
our $ currentlinenumber ; # Line number
our $ shorewall_dir ; #Shorewall Directory
2007-06-15 00:07:45 +02:00
#
# Initialize globals -- we take this novel approach to globals initialization to allow
# the compiler to run multiple times in the same process. The
# initialize() function does globals initialization for this
# module and is called from an INIT block below. The function is
# also called by Shorewall::Compiler::compiler at the beginning of
# the second and subsequent calls to that function.
#
2007-06-14 01:02:39 +02:00
sub initialize () {
#
# Misc Globals
#
% globals = ( SHAREDIR = > '/usr/share/shorewall' ,
2007-03-31 19:44:16 +02:00
CONFDIR = > '/etc/shorewall' ,
SHAREDIRPL = > '/usr/share/shorewall-perl/' ,
2007-04-27 17:15:13 +02:00
ORIGINAL_POLICY_MATCH = > '' ,
2007-03-31 19:44:16 +02:00
LOGPARMS = > '' ,
2007-04-23 22:44:24 +02:00
TC_SCRIPT = > '' ,
2007-06-14 22:27:40 +02:00
VERSION = > '4.0.0-Beta5' ,
2007-06-17 23:35:42 +02:00
CAPVERSION = > 30405 ,
2007-03-31 19:44:16 +02:00
) ;
2007-06-14 01:02:39 +02:00
#
# From shorewall.conf file
#
% config =
2007-04-18 22:53:25 +02:00
( STARTUP_ENABLED = > undef ,
2007-03-14 03:44:41 +01:00
VERBOSITY = > undef ,
#
# Logging
#
LOGFILE = > undef ,
LOGFORMAT = > undef ,
LOGTAGONLY = > undef ,
LOGRATE = > undef ,
LOGBURST = > undef ,
LOGALLNEW = > undef ,
BLACKLIST_LOGLEVEL = > undef ,
MACLIST_LOG_LEVEL = > undef ,
TCP_FLAGS_LOG_LEVEL = > undef ,
RFC1918_LOG_LEVEL = > undef ,
SMURF_LOG_LEVEL = > undef ,
LOG_MARTIANS = > undef ,
#
# Location of Files
#
IPTABLES = > undef ,
2007-04-01 17:20:07 +02:00
#
2007-03-14 03:44:41 +01:00
#PATH is inherited
2007-04-01 17:20:07 +02:00
#
2007-03-14 03:44:41 +01:00
PATH = > undef ,
SHOREWALL_SHELL = > undef ,
SUBSYSLOCK = > undef ,
MODULESDIR = > undef ,
2007-04-01 17:20:07 +02:00
#
2007-03-14 03:44:41 +01:00
#CONFIG_PATH is inherited
2007-04-01 17:20:07 +02:00
#
2007-03-14 03:44:41 +01:00
CONFIG_PATH = > undef ,
RESTOREFILE = > undef ,
IPSECFILE = > undef ,
2007-04-16 01:41:13 +02:00
LOCKFILE = > undef ,
2007-03-14 03:44:41 +01:00
#
# Default Actions/Macros
#
DROP_DEFAULT = > undef ,
REJECT_DEFAULT = > undef ,
ACCEPT_DEFAULT = > undef ,
QUEUE_DEFAULT = > undef ,
#
2007-05-13 19:00:19 +02:00
# RSH/RCP Commands
#
RSH_COMMAND = > undef ,
RCP_COMMAND = > undef ,
#
2007-03-14 03:44:41 +01:00
# Firewall Options
#
BRIDGING = > undef ,
IP_FORWARDING = > undef ,
ADD_IP_ALIASES = > undef ,
ADD_SNAT_ALIASES = > undef ,
RETAIN_ALIASES = > undef ,
TC_ENABLED = > undef ,
TC_EXPERT = > undef ,
CLEAR_TC = > undef ,
MARK_IN_FORWARD_CHAIN = > undef ,
CLAMPMSS = > undef ,
ROUTE_FILTER = > undef ,
DETECT_DNAT_IPADDRS = > undef ,
MUTEX_TIMEOUT = > undef ,
ADMINISABSENTMINDED = > undef ,
BLACKLISTNEWONLY = > undef ,
DELAYBLACKLISTLOAD = > undef ,
MODULE_SUFFIX = > undef ,
DISABLE_IPV6 = > undef ,
DYNAMIC_ZONES = > undef ,
PKTTYPE = > undef ,
RFC1918_STRICT = > undef ,
MACLIST_TABLE = > undef ,
MACLIST_TTL = > undef ,
SAVE_IPSETS = > undef ,
MAPOLDACTIONS = > undef ,
FASTACCEPT = > undef ,
IMPLICIT_CONTINUE = > undef ,
HIGH_ROUTE_MARKS = > undef ,
USE_ACTIONS = > undef ,
OPTIMIZE = > undef ,
EXPORTPARAMS = > undef ,
2007-03-28 18:59:15 +02:00
SHOREWALL_COMPILER = > undef ,
2007-03-14 03:44:41 +01:00
#
# Packet Disposition
#
MACLIST_DISPOSITION = > undef ,
TCP_FLAGS_DISPOSITION = > undef ,
BLACKLIST_DISPOSITION = > undef ,
) ;
2007-06-14 01:02:39 +02:00
#
# Config options and global settings that are to be copied to object script
#
@ propagateconfig = qw/ DISABLE_IPV6 MODULESDIR MODULE_SUFFIX LOGFORMAT SUBSYSLOCK LOCKFILE / ;
@ propagateenv = qw/ LOGLIMIT LOGTAGONLY LOGRULENUMBERS / ;
2007-03-14 03:44:41 +01:00
2007-06-14 01:02:39 +02:00
#
# From parsing the capabilities file
#
% capabilities =
2007-04-18 22:53:25 +02:00
( NAT_ENABLED = > undef ,
2007-03-14 03:44:41 +01:00
MANGLE_ENABLED = > undef ,
MULTIPORT = > undef ,
XMULTIPORT = > undef ,
CONNTRACK_MATCH = > undef ,
USEPKTTYPE = > undef ,
POLICY_MATCH = > undef ,
PHYSDEV_MATCH = > undef ,
LENGTH_MATCH = > undef ,
IPRANGE_MATCH = > undef ,
RECENT_MATCH = > undef ,
OWNER_MATCH = > undef ,
IPSET_MATCH = > undef ,
CONNMARK = > undef ,
XCONNMARK = > undef ,
CONNMARK_MATCH = > undef ,
XCONNMARK_MATCH = > undef ,
RAW_TABLE = > undef ,
IPP2P_MATCH = > undef ,
CLASSIFY_TARGET = > undef ,
ENHANCED_REJECT = > undef ,
KLUDGEFREE = > undef ,
MARK = > undef ,
XMARK = > undef ,
MANGLE_FORWARD = > undef ,
COMMENTS = > undef ,
ADDRTYPE = > undef ,
2007-06-17 23:35:42 +02:00
CAPVERSION = > undef ,
2007-03-14 03:44:41 +01:00
) ;
2007-06-14 01:02:39 +02:00
#
# /etc/protocols and /etc/services
#
% protocols = ( ) ;
% services = ( ) ;
#
# Capabilities
#
% capdesc = ( NAT_ENABLED = > 'NAT' ,
2007-06-05 18:49:13 +02:00
MANGLE_ENABLED = > 'Packet Mangling' ,
MULTIPORT = > 'Multi-port Match' ,
XMULTIPORT = > 'Extended Multi-port Match' ,
CONNTRACK_MATCH = > 'Connection Tracking Match' ,
USEPKTTYPE = > 'Packet Type Match' ,
POLICY_MATCH = > 'Policy Match' ,
PHYSDEV_MATCH = > 'Physdev Match' ,
LENGTH_MATCH = > 'Packet length Match' ,
IPRANGE_MATCH = > 'IP Range Match' ,
RECENT_MATCH = > 'Recent Match' ,
OWNER_MATCH = > 'Owner Match' ,
IPSET_MATCH = > 'Ipset Match' ,
CONNMARK = > 'CONNMARK Target' ,
XCONNMARK = > 'Extended CONNMARK Target' ,
CONNMARK_MATCH = > 'Connmark Match' ,
XCONNMARK_MATCH = > 'Extended Connmark Match' ,
RAW_TABLE = > 'Raw Table' ,
IPP2P_MATCH = > 'IPP2P Match' ,
CLASSIFY_TARGET = > 'CLASSIFY Target' ,
ENHANCED_REJECT = > 'Extended Reject' ,
KLUDGEFREE = > 'Repeat match' ,
MARK = > 'MARK Target' ,
XMARK = > 'Extended Mark Target' ,
MANGLE_FORWARD = > 'Mangle FORWARD Chain' ,
COMMENTS = > 'Comments' ,
ADDRTYPE = > 'Address Type Match' ,
2007-06-16 16:27:02 +02:00
TCPMSS_MATCH = > 'TCP MSS' ,
2007-06-17 23:35:42 +02:00
CAPVERSION = > 'Capability Version' ,
2007-06-05 18:49:13 +02:00
) ;
2007-06-14 01:02:39 +02:00
#
# Directories to search for configuration files
#
@ config_path = ( ) ;
#
# Stash away file references here when we encounter INCLUDE
#
@ includestack = ( ) ;
#
# Allow nested opens
#
@ openstack = ( ) ;
2007-03-29 20:57:53 +02:00
2007-06-14 01:02:39 +02:00
$ currentfile = undef ; # File handle reference
$ currentfilename = '' ; # File NAME
$ currentlinenumber = 0 ; # Line number
$ shorewall_dir = '' ; #Shorewall Directory
}
2007-03-31 19:29:17 +02:00
2007-06-14 01:02:39 +02:00
INIT {
initialize ;
}
2007-06-11 20:07:34 +02:00
2007-03-29 19:36:04 +02:00
#
# Issue a Warning Message
#
2007-04-08 16:42:26 +02:00
sub warning_message
2007-03-29 19:36:04 +02:00
{
2007-06-16 23:08:12 +02:00
my $ lineinfo = $ currentfile ? " : $currentfilename (line $currentlinenumber)" : '' ;
2007-03-30 01:07:15 +02:00
print STDERR " WARNING: @_$lineinfo\n" ;
2007-03-29 19:36:04 +02:00
}
2007-04-16 21:33:25 +02:00
#
# Issue fatal error message and die
#
2007-03-29 19:36:04 +02:00
sub fatal_error {
2007-06-16 23:08:12 +02:00
my $ lineinfo = $ currentfile ? " : $currentfilename (line $currentlinenumber)" : '' ;
2007-03-30 01:07:15 +02:00
2007-06-12 01:17:02 +02:00
die " ERROR: @_$lineinfo\n" ;
}
2007-03-29 19:36:04 +02:00
2007-06-12 01:17:02 +02:00
#
# Set $shorewall_dir
#
sub set_shorewall_dir ( $ ) {
$ shorewall_dir = shift ;
2007-03-29 19:36:04 +02:00
}
2007-03-14 03:44:41 +01:00
#
# Search the CONFIG_PATH for the passed file
#
2007-04-08 16:42:26 +02:00
sub find_file ($)
2007-03-14 03:44:41 +01:00
{
my $ filename = $ _ [ 0 ] ;
2007-04-16 21:33:25 +02:00
return $ filename if substr ( $ filename , 0 , 1 ) eq '/' ;
2007-03-14 03:44:41 +01:00
my $ directory ;
2007-03-31 00:38:09 +02:00
for $ directory ( @ config_path ) {
2007-03-30 01:07:15 +02:00
my $ file = "$directory$filename" ;
return $ file if - f $ file ;
2007-03-14 03:44:41 +01:00
}
2007-03-31 19:44:16 +02:00
"$globals{CONFDIR}/$filename" ;
2007-03-14 03:44:41 +01:00
}
2007-03-14 03:50:28 +01:00
2007-03-30 01:07:15 +02:00
#
# Pre-process a line from a configuration file.
2007-04-01 01:43:10 +02:00
2007-03-30 01:07:15 +02:00
# ensure that it has an appropriate number of columns.
# supply '-' in omitted trailing columns.
#
2007-04-01 17:38:05 +02:00
sub split_line ( $$$ ) {
my ( $ mincolumns , $ maxcolumns , $ description ) = @ _ ;
2007-03-30 01:07:15 +02:00
2007-05-10 17:29:41 +02:00
fatal_error "Shorewall Configuration file entries may not contain single quotes, double quotes, single back quotes or backslashes" if $ line =~ /["'`\\]/ ;
2007-05-17 16:10:46 +02:00
my @ line = split ( /\s+/ , $ line , $ maxcolumns + 1 ) ;
2007-05-10 17:29:41 +02:00
fatal_error "Invalid $description entry (too few columns)" if @ line < $ mincolumns ;
fatal_error "Invalid $description entry (too many columns)" if @ line > $ maxcolumns ;
push @ line , '-' while @ line < $ maxcolumns ;
@ line ;
}
2007-05-10 18:13:16 +02:00
#
# Version of 'split_line' that handles COMMENT lines
#
2007-05-10 17:29:41 +02:00
sub split_line1 ( $$$ ) {
my ( $ mincolumns , $ maxcolumns , $ description ) = @ _ ;
fatal_error "Shorewall Configuration file entries may not contain double quotes, single back quotes or backslashes" if $ line =~ /["`\\]/ ;
2007-05-17 16:10:46 +02:00
my @ line = split ( /\s+/ , $ line , $ maxcolumns + 1 ) ;
2007-05-10 17:29:41 +02:00
return @ line if $ line [ 0 ] eq 'COMMENT' ;
fatal_error "Shorewall Configuration file entries may not contain single quotes" if $ line =~ /'/ ;
fatal_error "Invalid $description entry (too few columns)" if @ line < $ mincolumns ;
fatal_error "Invalid $description entry (too many columns)" if @ line > $ maxcolumns ;
push @ line , '-' while @ line < $ maxcolumns ;
@ line ;
}
#
# When splitting a line in the rules file, don't pad out the columns with '-' if the first column contains one of these
#
my % no_pad = ( COMMENT = > 0 ,
SECTION = > 2 ) ;
2007-05-10 18:13:16 +02:00
#
# Version of 'split_line' used on rules file entries
#
2007-05-10 17:29:41 +02:00
sub split_line2 ( $$$ ) {
my ( $ mincolumns , $ maxcolumns , $ description ) = @ _ ;
2007-05-10 01:54:47 +02:00
fatal_error "Shorewall Configuration file entries may not contain double quotes, single back quotes or backslashes" if $ line =~ /["`\\]/ ;
2007-05-09 22:55:54 +02:00
2007-05-17 16:10:46 +02:00
my @ line = split ( /\s+/ , $ line , $ maxcolumns + 1 ) ;
2007-03-30 01:07:15 +02:00
2007-05-10 17:29:41 +02:00
my $ first = $ line [ 0 ] ;
my $ columns = $ no_pad { $ first } ;
if ( defined $ columns ) {
fatal_error "Invalid $first entry" if $ columns && @ line != $ columns ;
return @ line
}
2007-03-30 01:07:15 +02:00
2007-05-09 22:55:54 +02:00
fatal_error "Shorewall Configuration file entries may not contain single quotes" if $ line =~ /'/ ;
2007-04-01 17:38:05 +02:00
fatal_error "Invalid $description entry (too few columns)" if @ line < $ mincolumns ;
fatal_error "Invalid $description entry (too many columns)" if @ line > $ maxcolumns ;
2007-03-30 01:07:15 +02:00
2007-04-01 17:38:05 +02:00
push @ line , '-' while @ line < $ maxcolumns ;
2007-03-30 01:07:15 +02:00
@ line ;
}
2007-03-29 17:47:47 +02:00
#
2007-03-31 00:38:09 +02:00
# Open a file, setting $currentfile. Returns the file's absolute pathname if the file
2007-03-30 17:57:08 +02:00
# exists, is non-empty and was successfully opened. Terminates with a fatal error
# if the file exists, is non-empty, but the open fails.
2007-03-29 17:47:47 +02:00
#
2007-04-01 01:43:10 +02:00
sub do_open_file ( $ ) {
my $ fname = $ _ [ 0 ] ;
open $ currentfile , '<' , $ fname or fatal_error "Unable to open $fname: $!" ;
$ currentlinenumber = 0 ;
$ currentfilename = $ fname ;
}
2007-03-29 17:47:47 +02:00
sub open_file ( $ ) {
my $ fname = find_file $ _ [ 0 ] ;
fatal_error 'Internal Error in open_file()' if defined $ currentfile ;
2007-04-01 01:43:10 +02:00
do_open_file $ fname if - f $ fname && - s _ ;
2007-03-29 17:47:47 +02:00
}
2007-03-31 20:44:48 +02:00
#
2007-04-08 16:42:26 +02:00
# This function is normally called below in read_a_line() when EOF is reached. Clients of the
2007-03-31 20:44:48 +02:00
# module may also call the function to close the file before EOF
#
sub close_file () {
if ( $ currentfile ) {
close $ currentfile ;
2007-04-08 16:42:26 +02:00
2007-04-03 21:06:23 +02:00
my $ arrayref = pop @ includestack ;
2007-03-31 20:44:48 +02:00
if ( $ arrayref ) {
( $ currentfile , $ currentfilename , $ currentlinenumber ) = @$ arrayref ;
} else {
$ currentfile = undef ;
}
}
}
2007-04-08 16:35:31 +02:00
#
# The following two functions allow module clients to nest opens. This happens frequently
# in the Actions module.
#
2007-03-29 17:47:47 +02:00
sub push_open ( $ ) {
2007-04-03 21:06:23 +02:00
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
my @ a = @ includestack ;
push @ openstack , \ @ a ;
@ includestack = ( ) ;
2007-03-29 17:47:47 +02:00
$ currentfile = undef ;
open_file ( $ _ [ 0 ] ) ;
}
sub pop_open () {
2007-04-03 21:06:23 +02:00
@ includestack = @ { pop @ openstack } ;
2007-03-29 19:36:04 +02:00
2007-04-03 21:06:23 +02:00
my $ arrayref = pop @ includestack ;
2007-03-29 19:36:04 +02:00
if ( $ arrayref ) {
( $ currentfile , $ currentfilename , $ currentlinenumber ) = @$ arrayref ;
} else {
$ currentfile = undef ;
}
2007-04-08 16:42:26 +02:00
}
2007-03-29 17:47:47 +02:00
2007-03-29 19:02:13 +02:00
#
2007-04-08 16:35:31 +02:00
# Read a line from the current include stack.
2007-03-29 19:02:13 +02:00
#
# - Ignore blank or comment-only lines.
# - Remove trailing comments.
2007-04-01 01:43:10 +02:00
# - Handle Line Continuation
2007-03-29 19:02:13 +02:00
# - Expand shell variables from $ENV.
# - Handle INCLUDE <filename>
#
2007-03-29 06:22:10 +02:00
sub read_a_line {
2007-03-29 17:47:47 +02:00
while ( $ currentfile ) {
2007-03-29 16:24:35 +02:00
2007-03-29 19:02:13 +02:00
$ line = '' ;
while ( my $ nextline = <$currentfile> ) {
2007-03-30 17:57:08 +02:00
2007-03-29 19:36:04 +02:00
$ currentlinenumber + + ;
2007-03-31 01:21:08 +02:00
2007-04-01 01:43:10 +02:00
chomp $ nextline ;
#
2007-04-01 02:05:42 +02:00
# Continuation
2007-04-01 01:43:10 +02:00
#
2007-04-08 16:35:31 +02:00
if ( substr ( ( $ line . = $ nextline ) , - 1 , 1 ) eq '\\' ) {
$ line = substr ( $ line , 0 , - 1 ) ;
2007-03-29 19:02:13 +02:00
next ;
}
2007-04-01 16:07:06 +02:00
$ line =~ s/#.*$// ; # Remove Trailing Comments -- result might be a blank line
2007-04-01 02:05:42 +02:00
#
# Ignore ( concatenated ) Blank Lines
#
2007-04-08 16:42:26 +02:00
if ( $ line =~ /^\s*$/ ) {
2007-04-01 02:05:42 +02:00
$ line = '' ;
next ;
}
2007-04-01 02:10:17 +02:00
2007-04-01 01:43:10 +02:00
$ line =~ s/^\s+// ; # Remove Leading white space
$ line =~ s/\s+$// ; # Remove Trailing white space
2007-04-03 21:06:23 +02:00
2007-04-01 01:43:10 +02:00
#
2007-05-16 05:37:37 +02:00
# Expand Shell Variables using %ENV
2007-04-01 01:43:10 +02:00
#
$ line = join ( '' , $ 1 , ( $ ENV { $ 2 } || '' ) , $ 3 ) while $ line =~ /^(.*?)\${([a-zA-Z]\w*)}(.*)$/ ;
$ line = join ( '' , $ 1 , ( $ ENV { $ 2 } || '' ) , $ 3 ) while $ line =~ /^(.*?)\$([a-zA-Z]\w*)(.*)$/ ;
2007-04-08 16:42:26 +02:00
2007-04-01 16:07:06 +02:00
if ( $ line =~ /^INCLUDE\s/ ) {
2007-04-08 16:42:26 +02:00
2007-05-17 16:10:46 +02:00
my @ line = split /\s+/ , $ line , 3 ;
2007-04-08 16:42:26 +02:00
2007-04-08 16:35:31 +02:00
fatal_error "Invalid INCLUDE command: $line" if @ line != 2 ;
2007-04-03 21:06:23 +02:00
fatal_error "INCLUDEs nested too deeply: $line" if @ includestack >= 4 ;
2007-04-08 16:42:26 +02:00
2007-03-29 06:22:10 +02:00
my $ filename = find_file $ line [ 1 ] ;
2007-04-08 16:42:26 +02:00
2007-04-01 16:07:06 +02:00
fatal_error "INCLUDE file $filename not found" unless ( - f $ filename ) ;
2007-04-08 16:42:26 +02:00
2007-04-01 01:43:10 +02:00
if ( - s _ ) {
2007-04-03 21:06:23 +02:00
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
2007-04-01 01:43:10 +02:00
$ currentfile = undef ;
do_open_file $ filename ;
}
2007-04-01 01:58:13 +02:00
$ line = '' ;
2007-03-29 06:22:10 +02:00
} else {
return 1 ;
}
}
2007-04-08 16:42:26 +02:00
2007-03-31 20:44:48 +02:00
close_file ;
2007-03-29 06:22:10 +02:00
}
}
2007-04-16 21:33:25 +02:00
#
# Provide the passed default value for the passed configuration variable
#
2007-03-30 05:30:28 +02:00
sub default ( $$ ) {
my ( $ var , $ val ) = @ _ ;
$ config { $ var } = $ val unless defined $ config { $ var } && $ config { $ var } ne '' ;
}
2007-04-16 21:33:25 +02:00
#
# Provide a default value for a yes/no configuration variable.
#
2007-03-30 05:30:28 +02:00
sub default_yes_no ( $$ ) {
my ( $ var , $ val ) = @ _ ;
my $ curval = "\L$config{$var}" ;
2007-04-16 21:33:25 +02:00
if ( defined $ curval && $ curval ne '' ) {
2007-03-30 05:30:28 +02:00
if ( $ curval eq 'no' ) {
$ config { $ var } = '' ;
} else {
fatal_error "Invalid value for $var ($val)" unless $ curval eq 'yes' ;
}
} else {
$ config { $ var } = $ val ;
}
}
2007-04-24 16:53:45 +02:00
my % validlevels = ( debug = > 7 ,
info = > 6 ,
notice = > 5 ,
warning = > 4 ,
warn = > 4 ,
err = > 3 ,
error = > 3 ,
crit = > 2 ,
alert = > 1 ,
emerg = > 0 ,
panic = > 0 ,
2007-04-24 17:38:37 +02:00
none = > '' ,
2007-04-24 16:53:45 +02:00
ULOG = > 'ULOG' ) ;
#
2007-05-01 03:02:55 +02:00
# Validate a log level -- Drop the trailing '!' that some fools think is important.
2007-04-24 16:53:45 +02:00
#
sub validate_level ( $ ) {
my $ level = $ _ [ 0 ] ;
if ( defined $ level && $ level ne '' ) {
2007-05-01 02:01:24 +02:00
$ level =~ s/!$// ;
2007-04-24 16:53:45 +02:00
my $ value = $ validlevels { $ level } ;
return $ value if defined $ value ;
return $ level if $ level =~ /^[0-7]$/ ;
fatal_error "Invalid log level ($level)" ;
}
'' ;
}
#
# Validate a log level and supply default
#
sub default_log_level ( $$ ) {
my ( $ level , $ default ) = @ _ ;
my $ value = $ config { $ level } ;
2007-04-24 23:27:40 +02:00
unless ( defined $ value && $ value ne '' ) {
2007-04-24 16:53:45 +02:00
$ config { $ level } = $ default ;
} else {
$ config { $ level } = validate_level $ value ;
}
}
2007-04-22 00:41:47 +02:00
#
# Check a tri-valued variable
#
2007-04-22 21:30:42 +02:00
sub check_trivalue ( $$ ) {
my ( $ var , $ default ) = @ _ ;
2007-04-22 00:41:47 +02:00
my $ val = "\L$config{$var}" ;
2007-03-30 05:30:28 +02:00
2007-04-22 00:41:47 +02:00
if ( defined $ val ) {
2007-04-22 21:30:42 +02:00
if ( $ val eq 'yes' || $ val eq 'on' ) {
2007-04-22 21:45:27 +02:00
$ config { $ var } = 'on' ;
2007-04-22 21:30:42 +02:00
} elsif ( $ val eq 'no' || $ val eq 'off' ) {
2007-04-22 21:45:27 +02:00
$ config { $ var } = 'off' ;
2007-04-22 00:41:47 +02:00
} elsif ( $ val eq 'keep' ) {
$ config { $ var } = '' ;
2007-04-22 21:30:42 +02:00
} elsif ( $ val eq '' ) {
2007-04-23 21:49:02 +02:00
$ config { $ var } = $ default
2007-04-22 21:30:42 +02:00
} else {
2007-06-16 23:08:12 +02:00
fatal_error "Invalid value ($val) for $var" ;
2007-04-22 00:41:47 +02:00
}
2007-04-22 21:30:42 +02:00
} else {
$ config { var } = $ default
2007-04-22 00:41:47 +02:00
}
}
2007-04-16 21:33:25 +02:00
#
# Produce a report of the detected capabilities
#
2007-03-30 05:30:28 +02:00
sub report_capabilities () {
sub report_capability ( $ ) {
my $ cap = $ _ [ 0 ] ;
print " $capdesc{$cap}: " ;
print $ capabilities { $ cap } ? "Available\n" : "Not Available\n" ;
}
print "Shorewall has detected the following capabilities:\n" ;
for my $ cap ( sort { $ capdesc { $ a } cmp $ capdesc { $ b } } keys % capabilities ) {
report_capability $ cap ;
}
}
2007-04-16 21:33:25 +02:00
#
# Search the current PATH for the passed executable
#
2007-04-01 18:42:49 +02:00
sub mywhich ( $ ) {
my $ prog = $ _ [ 0 ] ;
for my $ dir ( split /:/ , $ ENV { PATH } ) {
return "$dir/$prog" if - x "$dir/$prog" ;
}
'' ;
}
2007-04-16 21:33:25 +02:00
#
# Load the kernel modules defined in the 'modules' file.
#
2007-04-01 21:30:09 +02:00
sub load_kernel_modules ( ) {
my $ moduleloader = mywhich 'modprobe' ? 'modprobe' : 'insmod' ;
my $ modulesdir = $ config { MODULESDIR } ;
unless ( $ modulesdir ) {
my $ uname = `uname -r` ;
fatal_error "The command 'uname -r' failed" unless $? == 0 ;
chomp $ uname ;
$ modulesdir = "/lib/modules/$uname/kernel/net/ipv4/netfilter:/lib/modules/$uname/kernel/net/netfilter" ;
}
my @ moduledirectories = split /:/ , $ modulesdir ;
if ( @ moduledirectories && open_file 'modules' ) {
my % loadedmodules ;
2007-04-08 16:42:26 +02:00
2007-04-01 21:30:09 +02:00
progress_message "Loading Modules..." ;
open LSMOD , '-|' , 'lsmod' or fatal_error "Can't run lsmod" ;
while ( $ line = <LSMOD> ) {
2007-05-17 16:10:46 +02:00
my $ module = ( split ( /\s+/ , $ line , 2 ) ) [ 0 ] ;
2007-04-02 19:47:05 +02:00
$ loadedmodules { $ module } = 1 unless $ module eq 'Module'
2007-04-01 21:30:09 +02:00
}
2007-04-08 16:42:26 +02:00
2007-04-01 21:30:09 +02:00
close LSMOD ;
$ config { MODULE_SUFFIX } = 'o gz ko o.gz ko.gz' unless $ config { MODULES_SUFFIX } ;
my @ suffixes = split /\s+/ , $ config { MODULE_SUFFIX } ;
while ( read_a_line ) {
fatal_error "Invalid modules file entry" unless ( $ line =~ /^loadmodule\s+([a-zA-Z]\w*)\s*(.*)$/ ) ;
my ( $ module , $ arguments ) = ( $ 1 , $ 2 ) ;
unless ( $ loadedmodules { $ module } ) {
2007-04-02 19:47:05 +02:00
for my $ directory ( @ moduledirectories ) {
for my $ suffix ( @ suffixes ) {
2007-04-01 21:30:09 +02:00
my $ modulefile = "$directory/$module.$suffix" ;
if ( - f $ modulefile ) {
if ( $ moduleloader eq 'insmod' ) {
system ( "insmod $modulefile $arguments" ) ;
} else {
system ( "modprobe $module $arguments" ) ;
}
$ loadedmodules { $ module } = 1 ;
}
}
}
}
}
2007-04-08 16:42:26 +02:00
}
2007-04-01 21:30:09 +02:00
}
2007-04-02 19:47:05 +02:00
#
# Q[uie]t version of system(). Returns true for success
#
sub qt ( $ ) {
system ( "@_ > /dev/null 2>&1" ) == 0 ;
}
2007-04-01 18:42:49 +02:00
#
# Determine which optional facilities are supported by iptables/netfilter
#
sub determine_capabilities () {
2007-04-08 16:42:26 +02:00
2007-05-02 23:59:11 +02:00
my $ iptables = $ config { IPTABLES } ;
my $ pid = $$ ;
my $ sillyname = "fooX$pid" ;
2007-04-01 18:42:49 +02:00
2007-04-02 19:47:05 +02:00
$ capabilities { NAT_ENABLED } = qt ( "$iptables -t nat -L -n" ) ;
$ capabilities { MANGLE_ENABLED } = qt ( "$iptables -t mangle -L -n" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
qt ( "$iptables -N $sillyname" ) ;
2007-04-08 16:42:26 +02:00
2007-05-02 23:59:11 +02:00
$ capabilities { CONNTRACK_MATCH } = qt ( "$iptables -A $sillyname -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT" ) ;
$ capabilities { MULTIPORT } = qt ( "$iptables -A $sillyname -p tcp -m multiport --dports 21,22 -j ACCEPT" ) ;
$ capabilities { XMULTIPORT } = qt ( "$iptables -A $sillyname -p tcp -m multiport --dports 21:22 -j ACCEPT" ) ;
$ capabilities { POLICY_MATCH } = qt ( "$iptables -A $sillyname -m policy --pol ipsec --mode tunnel --dir in -j ACCEPT" ) ;
$ capabilities { PHYSDEV_MATCH } = qt ( "$iptables -A $sillyname -m physdev --physdev-in eth0 -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
if ( qt ( "$iptables -A $sillyname -m iprange --src-range 192.168.1.5-192.168.1.124 -j ACCEPT" ) ) {
2007-04-01 18:42:49 +02:00
$ capabilities { IPRANGE_MATCH } = 1 ;
unless ( $ capabilities { KLUDGEFREE } ) {
2007-05-02 23:59:11 +02:00
$ capabilities { KLUDGEFREE } = qt ( "$iptables -A $sillyname -m iprange --src-range 192.168.1.5-192.168.1.124 -m iprange --dst-range 192.168.1.5-192.168.1.124 -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
}
}
2007-05-02 23:59:11 +02:00
$ capabilities { RECENT_MATCH } = qt ( "$iptables -A $sillyname -m recent --update -j ACCEPT" ) ;
$ capabilities { OWNER_MATCH } = qt ( "$iptables -A $sillyname -m owner --uid-owner 0 -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
if ( qt ( "$iptables -A $sillyname -m connmark --mark 2 -j ACCEPT" ) ) {
2007-04-01 18:42:49 +02:00
$ capabilities { CONNMARK_MATCH } = 1 ;
2007-05-02 23:59:11 +02:00
$ capabilities { XCONNMARK_MATCH } = qt ( "$iptables -A $sillyname -m connmark --mark 2/0xFF -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
}
2007-04-08 16:42:26 +02:00
2007-05-02 23:59:11 +02:00
$ capabilities { IPP2P_MATCH } = qt ( "$iptables -A $sillyname -p tcp -m ipp2p --ipp2p -j ACCEPT" ) ;
$ capabilities { LENGTH_MATCH } = qt ( "$iptables -A $sillyname -m length --length 10:20 -j ACCEPT" ) ;
$ capabilities { ENHANCED_REJECT } = qt ( "$iptables -A $sillyname -j REJECT --reject-with icmp-host-prohibited" ) ;
$ capabilities { COMMENTS } = qt ( qq( $iptables -A $sillyname -j ACCEPT -m comment --comment "This is a comment" ) ) ;
2007-04-01 18:42:49 +02:00
if ( $ capabilities { MANGLE_ENABLED } ) {
2007-05-02 23:59:11 +02:00
qt ( "$iptables -t mangle -N $sillyname" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
if ( qt ( "$iptables -t mangle -A $sillyname -j MARK --set-mark 1" ) ) {
2007-04-01 18:42:49 +02:00
$ capabilities { MARK } = 1 ;
2007-05-02 23:59:11 +02:00
$ capabilities { XMARK } = qt ( "$iptables -t mangle -A $sillyname -j MARK --and-mark 0xFF" ) ;
2007-04-01 18:42:49 +02:00
}
2007-05-02 23:59:11 +02:00
if ( qt ( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark" ) ) {
2007-04-01 18:42:49 +02:00
$ capabilities { CONNMARK } = 1 ;
2007-05-02 23:59:11 +02:00
$ capabilities { XCONNMARK } = qt ( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark --mask 0xFF" ) ;
2007-04-01 18:42:49 +02:00
}
2007-05-02 23:59:11 +02:00
$ capabilities { CLASSIFY_TARGET } = qt ( "$iptables -t mangle -A $sillyname -j CLASSIFY --set-class 1:1" ) ;
qt ( "$iptables -t mangle -F $sillyname" ) ;
qt ( "$iptables -t mangle -X $sillyname" ) ;
2007-04-01 18:42:49 +02:00
2007-04-02 19:47:05 +02:00
$ capabilities { MANGLE_FORWARD } = qt ( "$iptables -t mangle -L FORWARD -n" ) ;
2007-04-01 18:42:49 +02:00
}
2007-04-02 19:47:05 +02:00
$ capabilities { RAW_TABLE } = qt ( "$iptables -t raw -L -n" ) ;
2007-04-01 18:42:49 +02:00
if ( mywhich 'ipset' ) {
2007-05-02 23:59:11 +02:00
qt ( "ipset -X $sillyname" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
if ( qt ( "ipset -N $sillyname iphash" ) ) {
if ( qt ( "$iptables -A $sillyname -m set --set $sillyname src -j ACCEPT" ) ) {
qt ( "$iptables -D $sillyname -m set --set $sillyname src -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
$ capabilities { IPSET_MATCH } = 1 ;
}
2007-05-02 23:59:11 +02:00
qt ( "ipset -X $sillyname" ) ;
2007-04-01 18:42:49 +02:00
}
}
2007-06-16 16:27:02 +02:00
$ capabilities { USEPKTTYPE } = qt ( "$iptables -A $sillyname -m pkttype --pkt-type broadcast -j ACCEPT" ) ;
$ capabilities { ADDRTYPE } = qt ( "$iptables -A $sillyname -m addrtype --src-type BROADCAST -j ACCEPT" ) ;
$ capabilities { TCPMSS_MATCH } = qt ( "$iptables -A $sillyname -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1000:1500 -j ACCEPT" ) ;
2007-04-01 18:42:49 +02:00
2007-05-02 23:59:11 +02:00
qt ( "$iptables -F $sillyname" ) ;
qt ( "$iptables -X $sillyname" ) ;
2007-06-17 23:35:42 +02:00
$ capabilities { CAPVERSION } = $ globals { CAPVERSION } ;
2007-04-08 16:42:26 +02:00
}
2007-04-01 18:42:49 +02:00
2007-04-16 21:33:25 +02:00
#
# Require the passed capability
#
2007-05-04 17:12:29 +02:00
sub require_capability ( $$$ ) {
my ( $ capability , $ description , $ singular ) = @ _ ;
2007-03-30 05:30:28 +02:00
2007-05-04 17:12:29 +02:00
fatal_error "$description require${singular} $capdesc{$capability} in your kernel and iptables"
2007-03-30 05:30:28 +02:00
unless $ capabilities { $ capability } ;
}
2007-04-03 03:20:56 +02:00
#
# Set default config path
#
2007-05-16 05:37:37 +02:00
sub ensure_config_path () {
2007-04-03 03:20:56 +02:00
my $ f = "$globals{SHAREDIR}/configpath" ;
2007-05-16 05:37:37 +02:00
$ globals { CONFDIR } = '/usr/share/shorewall/configfiles/' if $> != 0 ;
2007-04-08 16:42:26 +02:00
2007-04-03 03:20:56 +02:00
unless ( $ config { CONFIG_PATH } ) {
fatal_error "$f does not exist" unless - f $ f ;
2007-04-08 16:42:26 +02:00
2007-04-07 19:14:55 +02:00
open_file $ f ;
2007-04-03 03:20:56 +02:00
2007-05-16 06:01:08 +02:00
$ ENV { CONFDIR } = $ globals { CONFDIR } ;
2007-04-03 03:20:56 +02:00
while ( read_a_line ) {
if ( $ line =~ /^\s*([a-zA-Z]\w*)=(.*?)\s*$/ ) {
my ( $ var , $ val ) = ( $ 1 , $ 2 ) ;
$ config { $ var } = ( $ val =~ /\"([^\"]*)\"$/ ? $ 1 : $ val ) if exists $ config { $ var } ;
} else {
fatal_error "Unrecognized entry" ;
}
}
2007-04-08 16:42:26 +02:00
2007-04-03 03:20:56 +02:00
fatal_error "CONFIG_PATH not found in $f" unless $ config { CONFIG_PATH } ;
}
@ config_path = split /:/ , $ config { CONFIG_PATH } ;
for ( @ config_path ) {
2007-04-18 22:53:25 +02:00
$ _ . = '/' unless m | // $| ;
2007-04-03 03:20:56 +02:00
}
2007-06-11 20:07:34 +02:00
if ( $ shorewall_dir ) {
$ shorewall_dir . = '/' unless $ shorewall_dir =~ m | // $| ;
unshift @ config_path , $ shorewall_dir if $ shorewall_dir ne $ config_path [ 0 ] ;
2007-04-03 03:20:56 +02:00
}
}
2007-03-14 03:44:41 +01:00
#
2007-03-29 16:24:35 +02:00
# - Read the shorewall.conf file
2007-04-16 21:33:25 +02:00
# - Read the capabilities file, if any
2007-03-31 19:44:16 +02:00
# - establish global hashes %config , %globals and %capabilities
2007-03-14 03:44:41 +01:00
#
2007-03-31 19:44:16 +02:00
sub get_configuration ( $ ) {
my $ export = $ _ [ 0 ] ;
2007-03-31 00:38:09 +02:00
2007-05-16 05:37:37 +02:00
ensure_config_path ;
2007-04-03 03:20:56 +02:00
2007-03-14 03:44:41 +01:00
my $ file = find_file 'shorewall.conf' ;
if ( - f $ file ) {
if ( - r _ ) {
2007-03-30 01:07:15 +02:00
open_file $ file ;
2007-03-14 03:44:41 +01:00
2007-03-29 06:22:10 +02:00
while ( read_a_line ) {
2007-03-31 01:31:22 +02:00
if ( $ line =~ /^\s*([a-zA-Z]\w*)=(.*?)\s*$/ ) {
2007-03-14 03:44:41 +01:00
my ( $ var , $ val ) = ( $ 1 , $ 2 ) ;
unless ( exists $ config { $ var } ) {
2007-04-03 03:20:56 +02:00
warning_message "Unknown configuration option ($var) ignored" ;
2007-03-14 03:44:41 +01:00
next ;
}
2007-03-31 01:21:08 +02:00
$ config { $ var } = ( $ val =~ /\"([^\"]*)\"$/ ? $ 1 : $ val ) ;
2007-03-14 03:44:41 +01:00
} else {
2007-04-03 03:20:56 +02:00
fatal_error "Unrecognized entry" ;
2007-03-14 03:44:41 +01:00
}
}
} else {
fatal_error "Cannot read $file (Hint: Are you root?)" ;
}
} else {
fatal_error "$file does not exist!" ;
}
2007-05-16 05:37:37 +02:00
ensure_config_path ;
2007-03-14 03:44:41 +01:00
2007-04-23 22:24:28 +02:00
default 'PATH' , '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin' ;
2007-04-01 18:42:49 +02:00
default 'MODULE_PREFIX' , 'o gz ko o.gz ko.gz' ;
2007-03-14 03:44:41 +01:00
2007-04-02 00:04:35 +02:00
if ( ! $ export && $> == 0 ) { # $> == $EUID
2007-04-01 18:42:49 +02:00
unless ( $ config { IPTABLES } ) {
$ config { IPTABLES } = mywhich 'iptables' ;
fatal_error "Can't find iptables executable" unless $ config { IPTABLES } ;
2007-03-14 03:44:41 +01:00
} else {
2007-05-01 00:25:34 +02:00
fatal_error "\$IPTABLES=$config{IPTABLES} does not exist or is not executable" unless - x $ config { IPTABLES } ;
2007-04-01 18:42:49 +02:00
}
2007-04-01 21:30:09 +02:00
load_kernel_modules ;
2007-04-08 16:42:26 +02:00
2007-04-01 18:42:49 +02:00
unless ( open_file 'capabilities' ) {
determine_capabilities ;
2007-03-14 03:44:41 +01:00
}
2007-04-23 22:44:24 +02:00
} else {
2007-05-16 05:37:37 +02:00
open_file 'capabilities' or fatal_error "The -e flag requires a capabilities file" ;
2007-03-14 03:44:41 +01:00
}
2007-04-02 19:47:05 +02:00
2007-04-01 19:05:27 +02:00
#
# If we successfully called open_file above, then this loop will read the capabilities file.
# Otherwise, the first call to read_a_line() below will return false
#
2007-04-01 18:42:49 +02:00
while ( read_a_line ) {
2007-04-01 19:05:27 +02:00
if ( $ line =~ /^([a-zA-Z]\w*)=(.*)$/ ) {
2007-04-01 18:42:49 +02:00
my ( $ var , $ val ) = ( $ 1 , $ 2 ) ;
unless ( exists $ capabilities { $ var } ) {
2007-04-02 00:13:27 +02:00
warning_message "Unknown capability ($var) ignored" ;
2007-04-01 18:42:49 +02:00
next ;
}
2007-03-14 03:44:41 +01:00
2007-04-01 18:42:49 +02:00
$ capabilities { $ var } = $ val =~ /^\"([^\"]*)\"$/ ? $ 1 : $ val ;
} else {
2007-04-01 19:05:27 +02:00
fatal_error "Unrecognized capabilities entry" ;
2007-04-01 18:42:49 +02:00
}
}
2007-03-14 03:44:41 +01:00
2007-06-17 23:35:42 +02:00
if ( $ capabilities { CAPVERSION } ) {
warning_message "Your capabilities file is out of date -- it does not contain all of the capabilities defined by Shorewall version $globals{VERSION}" unless $ capabilities { CAPVERSION } >= $ globals { CAPVERSION } ;
} else {
2007-06-18 00:13:00 +02:00
warning_message "Your capabilities file may not contain all of the capabilities defined by Shorewall version $globals{VERSION}" ;
2007-06-17 23:35:42 +02:00
}
2007-04-27 17:15:13 +02:00
$ globals { ORIGINAL_POLICY_MATCH } = $ capabilities { POLICY_MATCH } ;
2007-03-14 03:44:41 +01:00
if ( $ config { LOGRATE } || $ config { LOGBURST } ) {
2007-05-08 04:34:58 +02:00
$ globals { LOGLIMIT } = '-m limit ' ;
$ globals { LOGLIMIT } . = "--limit $config{LOGRATE} " if $ config { LOGRATE } ;
$ globals { LOGLIMIT } . = "--limit-burst $config{LOGBURST} " if $ config { LOGBURST } ;
2007-03-14 03:44:41 +01:00
} else {
2007-03-31 19:44:16 +02:00
$ globals { LOGLIMIT } = '' ;
2007-03-14 03:44:41 +01:00
}
2007-04-22 21:45:27 +02:00
check_trivalue ( 'IP_FORWARDING' , 'on' ) ;
check_trivalue ( 'ROUTE_FILTER' , '' ) ;
check_trivalue ( 'LOG_MARTIANS' , '' ) ;
2007-03-14 03:44:41 +01:00
default_yes_no 'ADD_IP_ALIASES' , 'Yes' ;
default_yes_no 'ADD_SNAT_ALIASES' , '' ;
default_yes_no 'DETECT_DNAT_IPADDRS' , '' ;
default_yes_no 'DETECT_DNAT_IPADDRS' , '' ;
default_yes_no 'CLEAR_TC' , 'Yes' ;
2007-06-11 20:07:34 +02:00
2007-04-23 21:49:02 +02:00
if ( defined $ config { CLAMPMSS } ) {
default_yes_no 'CLAMPMSS' , '' unless $ config { CLAMPMSS } =~ /^\d+$/ ;
} else {
$ config { CLAMPMSS } = '' ;
}
2007-03-14 03:44:41 +01:00
2007-03-23 22:24:28 +01:00
unless ( $ config { ADD_IP_ALIASES } || $ config { ADD_SNAT_ALIASES } ) {
2007-03-14 03:44:41 +01:00
$ config { RETAIN_ALIASES } = '' ;
} else {
default_yes_no 'RETAIN_ALIASES' , '' ;
}
default_yes_no 'ADMINISABSENTMINDED' , '' ;
default_yes_no 'BLACKLISTNEWONLY' , '' ;
default_yes_no 'DISABLE_IPV6' , '' ;
default_yes_no 'DYNAMIC_ZONES' , '' ;
2007-03-31 19:44:16 +02:00
fatal_error "DYNAMIC_ZONES=Yes is incompatible with the -e option" if $ config { DYNAMIC_ZONES } && $ export ;
2007-03-24 20:19:29 +01:00
default_yes_no 'BRIDGING' , '' ;
2007-03-31 19:44:16 +02:00
fatal_error 'BRIDGING=Yes is not supported by Shorewall-perl' . $ globals { VERSION } if $ config { BRIDGING } ;
2007-03-27 01:17:46 +02:00
2007-03-14 03:44:41 +01:00
default_yes_no 'STARTUP_ENABLED' , 'Yes' ;
default_yes_no 'DELAYBLACKLISTLOAD' , '' ;
2007-04-01 17:20:07 +02:00
warning_message 'DELAYBLACKLISTLOAD=Yes is not supported by Shorewall-perl ' . $ globals { VERSION } if $ config { DELAYBLACKLISTLOAD } ;
2007-03-14 03:44:41 +01:00
default_yes_no 'LOGTAGONLY' , '' ;
default_yes_no 'RFC1918_STRICT' , '' ;
default_yes_no 'SAVE_IPSETS' , '' ;
2007-03-24 18:16:13 +01:00
2007-03-31 19:44:16 +02:00
warning_message 'SAVE_IPSETS=Yes is not supported by Shorewall-perl ' . $ globals { VERSION } if $ config { SAVE_IPSETS } ;
2007-03-24 18:16:13 +01:00
2007-03-14 03:44:41 +01:00
default_yes_no 'MAPOLDACTIONS' , '' ;
2007-03-24 18:16:13 +01:00
2007-03-31 19:44:16 +02:00
warning_message 'MAPOLDACTIONS=Yes is not supported by Shorewall-perl ' . $ globals { VERSION } if $ config { MAPOLDACTIONS } ;
2007-03-24 18:16:13 +01:00
2007-03-14 03:44:41 +01:00
default_yes_no 'FASTACCEPT' , '' ;
2007-04-22 23:42:35 +02:00
fatal_error "BLACKLISTNEWONLY=No may not be specified with FASTACCEPT=Yes" if $ config { FASTACCEPT } && ! $ config { BLACKLISTNEWONLY } ;
2007-03-14 03:44:41 +01:00
default_yes_no 'IMPLICIT_CONTINUE' , '' ;
default_yes_no 'HIGH_ROUTE_MARKS' , '' ;
default_yes_no 'TC_EXPERT' , '' ;
default_yes_no 'USE_ACTIONS' , 'Yes' ;
2007-03-31 20:44:48 +02:00
warning_message 'USE_ACTIONS=No is not supported by Shorewall-perl ' . $ globals { VERSION } unless $ config { USE_ACTIONS } ;
2007-03-14 03:44:41 +01:00
default_yes_no 'EXPORTPARAMS' , '' ;
2007-03-25 18:38:00 +02:00
default_yes_no 'MARK_IN_FORWARD_CHAIN' , '' ;
2007-03-14 03:44:41 +01:00
$ capabilities { XCONNMARK } = '' unless $ capabilities { XCONNMARK_MATCH } and $ capabilities { XMARK } ;
default 'BLACKLIST_DISPOSITION' , 'DROP' ;
2007-03-27 01:17:46 +02:00
2007-04-24 16:53:45 +02:00
default_log_level 'BLACKLIST_LOGLEVEL' , '' ;
default_log_level 'MACLIST_LOG_LEVEL' , '' ;
default_log_level 'TCP_FLAGS_LOG_LEVEL' , '' ;
2007-04-24 23:27:40 +02:00
default_log_level 'RFC1918_LOG_LEVEL' , 6 ;
2007-04-24 16:53:45 +02:00
default_log_level 'SMURF_LOG_LEVEL' , '' ;
default_log_level 'LOGALLNEW' , '' ;
2007-03-14 03:44:41 +01:00
my $ val ;
2007-03-31 19:44:16 +02:00
$ globals { MACLIST_TARGET } = 'reject' ;
2007-03-14 03:44:41 +01:00
if ( $ val = $ config { MACLIST_DISPOSITION } ) {
unless ( $ val eq 'REJECT' ) {
if ( $ val eq 'DROP' ) {
2007-03-31 19:44:16 +02:00
$ globals { MACLIST_TARGET } = 'DROP' ;
2007-03-14 03:44:41 +01:00
} elsif ( $ val eq 'ACCEPT' ) {
2007-03-31 19:44:16 +02:00
$ globals { MACLIST_TARGET } = 'RETURN' ;
2007-03-14 03:44:41 +01:00
} else {
2007-06-16 23:08:12 +02:00
fatal_error "Invalid value ($config{MACLIST_DISPOSITION}) for MACLIST_DISPOSITION"
2007-03-14 03:44:41 +01:00
}
}
} else {
$ config { MACLIST_DISPOSITION } = 'REJECT' ;
}
2007-03-27 01:17:46 +02:00
2007-03-14 03:44:41 +01:00
if ( $ val = $ config { MACLIST_TABLE } ) {
if ( $ val eq 'mangle' ) {
fatal_error 'MACLIST_DISPOSITION=REJECT is not allowed with MACLIST_TABLE=mangle' if $ config { MACLIST_DISPOSITION } eq 'REJECT' ;
} else {
fatal_error "Invalid value ($val) for MACLIST_TABLE option" unless $ val eq 'filter' ;
}
2007-04-08 16:42:26 +02:00
} else {
2007-03-14 03:44:41 +01:00
default 'MACLIST_TABLE' , 'filter' ;
}
if ( $ val = $ config { TCP_FLAGS_DISPOSITION } ) {
fatal_error "Invalid value ($config{TCP_FLAGS_DISPOSITION}) for TCP_FLAGS_DISPOSITION" unless $ val =~ /^(REJECT|ACCEPT|DROP)$/ ;
} else {
$ config { TCP_FLAGS_DISPOSITION } = 'DROP' ;
}
2007-03-27 01:17:46 +02:00
2007-04-23 21:49:02 +02:00
default 'TC_ENABLED' , 'Internal' ;
2007-04-24 01:17:30 +02:00
$ val = "\L$config{TC_ENABLED}" ;
if ( $ val eq 'yes' ) {
$ file = find_file 'tcstart' ;
fatal_error "Unable to find tcstart file" unless - f $ file ;
$ globals { TC_SCRIPT } = $ file ;
} elsif ( $ val ne 'internal' ) {
fatal_error "Invalid value ($config{TC_ENABLED}) for TC_ENABLED" unless $ val eq 'no' ;
$ config { TC_ENABLED } = '' ;
2007-03-14 03:44:41 +01:00
}
default 'RESTOREFILE' , 'restore' ;
default 'DROP_DEFAULT' , 'Drop' ;
default 'REJECT_DEFAULT' , 'Reject' ;
default 'QUEUE_DEFAULT' , 'none' ;
default 'ACCEPT_DEFAULT' , 'none' ;
default 'OPTIMIZE' , 0 ;
2007-04-23 21:49:02 +02:00
default 'IPSECFILE' , 'zones' ;
2007-03-27 01:17:46 +02:00
2007-04-01 17:38:05 +02:00
fatal_error 'IPSECFILE=ipsec is not supported by Shorewall-perl ' . $ globals { VERSION } unless $ config { IPSECFILE } eq 'zones' ;
2007-04-01 17:20:07 +02:00
2007-03-14 03:44:41 +01:00
for my $ default qw/DROP_DEFAULT REJECT_DEFAULT QUEUE_DEFAULT ACCEPT_DEFAULT/ {
$ config { $ default } = 'none' if "\L$config{$default}" eq 'none' ;
}
$ val = $ config { OPTIMIZE } ;
fatal_error "Invalid OPTIMIZE value ($val)" unless ( $ val eq '0' ) || ( $ val eq '1' ) ;
fatal_error "Invalid IPSECFILE value ($config{IPSECFILE}" unless $ config { IPSECFILE } eq 'zones' ;
2007-03-31 19:44:16 +02:00
$ globals { MARKING_CHAIN } = $ config { MARK_IN_FORWARD_CHAIN } ? 'tcfor' : 'tcpre' ;
2007-03-14 03:44:41 +01:00
if ( $ val = $ config { LOGFORMAT } ) {
my $ result ;
eval {
if ( $ val =~ /%d/ ) {
2007-03-31 19:44:16 +02:00
$ globals { LOGRULENUMBERS } = 'Yes' ;
2007-03-14 03:44:41 +01:00
$ result = sprintf "$val" , 'fooxx2barxx' , 1 , 'ACCEPT' ;
} else {
$ result = sprintf "$val" , 'fooxx2barxx' , 'ACCEPT' ;
}
} ;
fatal_error "Invalid LOGFORMAT ($val)" if $@ ;
2007-03-27 01:17:46 +02:00
2007-06-16 23:08:12 +02:00
fatal_error "LOGFORMAT string is longer than 29 characters ($val)" if length $ result > 29 ;
2007-03-14 03:44:41 +01:00
2007-03-31 19:44:16 +02:00
$ globals { MAXZONENAMELENGTH } = int ( 5 + ( ( 29 - ( length $ result ) ) / 2 ) ) ;
2007-03-14 03:44:41 +01:00
} else {
2007-04-23 21:49:02 +02:00
$ config { LOGFORMAT } = 'Shorewall:%s:%s:' ;
2007-03-31 19:44:16 +02:00
$ globals { MAXZONENAMELENGTH } = 5 ;
2007-03-14 03:44:41 +01:00
}
2007-04-16 01:41:13 +02:00
if ( $ config { LOCKFILE } ) {
my ( $ file , $ dir , $ suffix ) ;
eval {
( $ file , $ dir , $ suffix ) = fileparse ( $ config { LOCKFILE } ) ;
} ;
die $@ if $@ ;
fatal_error "LOCKFILE=$config{LOCKFILE}: Directory $dir does not exist" unless - d $ dir ;
} else {
$ config { LOCKFILE } = '' ;
}
2007-04-24 21:53:13 +02:00
open_file '/etc/protocols' or fatal_error "Cannot open /etc/protocols: $!" ;
while ( read_a_line ) {
my ( $ proto1 , $ number , $ proto2 , $ proto3 ) = split_line ( 2 , 4 , '/etc/protocols entry' ) ;
$ protocols { $ proto1 } = $ number ;
$ protocols { $ proto2 } = $ number unless $ proto2 eq '-' || $ proto3 ne '-' ;
}
open_file '/etc/services' or fatal_error "Cannot open /etc/services: $!" ;
while ( read_a_line ) {
my ( $ name1 , $ proto_number , @ names ) = split_line ( 2 , 10 , '/etc/services entry' ) ;
my ( $ number , $ proto ) = split '/' , $ proto_number ;
$ services { $ name1 } = $ number ;
while ( defined ( $ name1 = shift @ names ) && $ name1 ne '-' ) {
$ services { $ name1 } = $ number ;
}
}
2007-03-14 03:44:41 +01:00
}
2007-04-16 21:33:25 +02:00
#
2007-06-05 18:49:13 +02:00
# The values of the options in @propagateconfig are copied to the object file in OPTION=<value> format.
2007-04-16 21:33:25 +02:00
#
2007-03-14 03:44:41 +01:00
sub propagateconfig () {
2007-06-05 18:49:13 +02:00
for my $ option ( @ propagateconfig ) {
2007-03-14 03:44:41 +01:00
my $ value = $ config { $ option } || '' ;
emit "$option=\"$value\"" ;
}
2007-03-27 01:17:46 +02:00
2007-06-05 18:49:13 +02:00
for my $ option ( @ propagateenv ) {
2007-03-31 19:44:16 +02:00
my $ value = $ globals { $ option } || '' ;
2007-03-14 03:44:41 +01:00
emit "$option=\"$value\"" ;
}
}
2007-04-16 21:33:25 +02:00
#
2007-06-03 23:44:17 +02:00
# Add a shell script file to the output script -- Return true if the
# file exists and is not in /usr/share/shorewall/.
2007-04-16 21:33:25 +02:00
#
2007-03-14 05:06:32 +01:00
sub append_file ( $ ) {
my $ user_exit = find_file $ _ [ 0 ] ;
2007-06-03 23:44:17 +02:00
my $ result = 0 ;
2007-03-14 05:06:32 +01:00
2007-06-06 00:13:58 +02:00
unless ( $ user_exit =~ /^($globals{SHAREDIR})/ ) {
2007-03-14 05:06:32 +01:00
if ( - f $ user_exit ) {
2007-06-03 23:44:17 +02:00
$ result = 1 ;
2007-03-14 05:06:32 +01:00
save_progress_message "Processing $user_exit ..." ;
copy1 $ user_exit ;
}
2007-03-27 01:17:46 +02:00
}
2007-06-03 23:44:17 +02:00
$ result ;
2007-03-14 05:06:32 +01:00
}
2007-03-23 00:06:16 +01:00
#
# Run a Perl extension script
#
sub run_user_exit ( $ ) {
my $ chainref = $ _ [ 0 ] ;
my $ file = find_file $ chainref - > { name } ;
if ( - f $ file ) {
progress_message "Processing $file..." ;
2007-05-18 20:13:46 +02:00
unless ( my $ return = eval `cat $file` ) {
2007-03-23 00:06:16 +01:00
fatal_error "Couldn't parse $file: $@" if $@ ;
fatal_error "Couldn't do $file: $!" unless defined $ return ;
2007-05-18 20:13:46 +02:00
fatal_error "Couldn't run $file" ;
2007-03-23 00:06:16 +01:00
}
}
}
2007-05-20 18:25:53 +02:00
sub run_user_exit1 ( $ ) {
my $ file = find_file $ _ [ 0 ] ;
if ( - f $ file ) {
progress_message "Processing $file..." ;
#
# File may be empty -- in which case eval would fail
#
push_open $ file ;
if ( read_a_line ) {
close_file ;
unless ( my $ return = eval `cat $file` ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
fatal_error "Couldn't do $file: $!" unless defined $ return ;
fatal_error "Couldn't run $file" ;
}
}
2007-05-20 18:37:09 +02:00
pop_open ;
}
}
sub run_user_exit2 ( $$ ) {
my ( $ file , $ chainref ) = ( find_file $ _ [ 0 ] , $ _ [ 1 ] ) ;
if ( - f $ file ) {
progress_message "Processing $file..." ;
#
# File may be empty -- in which case eval would fail
#
push_open $ file ;
if ( read_a_line ) {
close_file ;
unless ( my $ return = eval `cat $file` ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
fatal_error "Couldn't do $file: $!" unless defined $ return ;
fatal_error "Couldn't run $file" ;
}
}
pop_open ;
2007-05-20 18:25:53 +02:00
}
}
2007-04-16 21:33:25 +02:00
#
# Generate the aux config file for Shorewall Lite
#
2007-03-17 19:18:54 +01:00
sub generate_aux_config () {
sub conditionally_add_option ( $ ) {
my $ option = $ _ [ 0 ] ;
my $ value = $ config { $ option } ;
2007-04-14 00:37:23 +02:00
emit "[ -n \"\${$option:=$value}\" ]" if $ value ne '' ;
2007-03-17 19:18:54 +01:00
}
sub conditionally_add_option1 ( $ ) {
my $ option = $ _ [ 0 ] ;
my $ value = $ config { $ option } ;
emit "$option=\"$value\"" if $ value ;
}
create_temp_aux_config ;
2007-04-01 00:03:16 +02:00
emit join ( '' , "#\n# Shorewall auxiliary configuration file created by Shorewall-perl version " , $ globals { VERSION } , ' - ' , localtime , "\n#" ) ;
2007-03-27 01:17:46 +02:00
2007-04-16 01:41:13 +02:00
for my $ option qw( VERBOSITY LOGFILE LOGFORMAT IPTABLES PATH SHOREWALL_SHELL SUBSYSLOCK LOCKFILE RESTOREFILE SAVE_IPSETS ) {
2007-03-17 19:18:54 +01:00
conditionally_add_option $ option ;
}
conditionally_add_option1 'TC_ENABLED' ;
finalize_aux_config ;
}
1 ;