2009-02-22 18:30:14 +01:00
#
2009-06-13 16:07:55 +02:00
# Shorewall 4.4 -- /usr/share/shorewall/Shorewall/Config.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]
#
2010-01-01 21:58:27 +01:00
# (c) 2007,2008,2009,2010 - Tom Eastep (teastep@shorewall.net)
2009-02-22 18:30:14 +01:00
#
# Complete documentation is available at http://shorewall.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of Version 2 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# 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. The module also provides the basic
2009-10-06 00:43:29 +02:00
# output file services such as creation of temporary 'script' files, writing
2009-02-22 18:30:14 +01:00
# into those files (emitters) and finalizing those files (renaming
# them to their final name and setting their mode appropriately).
#
package Shorewall::Config ;
use strict ;
use warnings ;
use File::Basename ;
use File::Temp qw/ tempfile tempdir / ;
use Cwd qw( abs_path getcwd ) ;
use autouse 'Carp' = > qw( longmess confess ) ;
use Scalar::Util 'reftype' ;
our @ ISA = qw( Exporter ) ;
#
# Imported variables should be treated as read-only by importers
#
our @ EXPORT = qw(
warning_message
fatal_error
2009-03-09 21:56:53 +01:00
assert
2009-02-22 18:30:14 +01:00
progress_message
progress_message_nocompress
progress_message2
progress_message3
) ;
our @ EXPORT_OK = qw( $shorewall_dir initialize read_a_line1 set_config_path shorewall ) ;
2009-10-06 00:43:29 +02:00
our % EXPORT_TAGS = ( internal = > [ qw( create_temp_script
finalize_script
enable_script
disable_script
2009-02-22 18:30:14 +01:00
numeric_value
numeric_value1
2009-04-23 21:43:57 +02:00
hex_value
2009-02-22 18:30:14 +01:00
in_hex
in_hex2
in_hex3
in_hex4
in_hex8
2009-04-23 21:43:57 +02:00
in_hexp
2009-02-22 18:30:14 +01:00
emit
2010-01-11 23:16:03 +01:00
emitstd
2009-02-22 18:30:14 +01:00
emit_unindented
save_progress_message
save_progress_message_short
set_timestamp
2009-08-22 16:57:55 +02:00
set_verbosity
2009-02-22 18:30:14 +01:00
set_log
close_log
set_command
push_indent
pop_indent
copy
2009-06-19 23:39:45 +02:00
copy1
2009-02-22 18:30:14 +01:00
create_temp_aux_config
finalize_aux_config
set_shorewall_dir
set_debug
find_file
split_list
split_list1
split_line
split_line1
first_entry
open_file
close_file
push_open
pop_open
read_a_line
validate_level
qt
ensure_config_path
get_configuration
require_capability
2010-01-25 16:56:16 +01:00
have_capability
2009-02-22 18:30:14 +01:00
report_capabilities
propagateconfig
append_file
run_user_exit
run_user_exit1
run_user_exit2
generate_aux_config
$ product
$ Product
$ command
$ doing
$ done
$ currentline
% config
% globals
F_IPV4
F_IPV6
MIN_VERBOSITY
MAX_VERBOSITY
2009-08-20 23:32:15 +02:00
) ] ) ;
2009-02-22 18:30:14 +01:00
Exporter:: export_ok_tags ( 'internal' ) ;
2010-01-16 18:53:53 +01:00
our $ VERSION = '4.4_7' ;
2009-02-22 18:30:14 +01:00
#
# describe the current command, it's present progressive, and it's completion.
#
our ( $ command , $ doing , $ done ) ;
#
# VERBOSITY
#
2009-08-22 16:57:55 +02:00
our $ verbosity ;
2009-02-22 18:30:14 +01:00
#
# Logging
#
2009-08-22 16:57:55 +02:00
our ( $ log , $ log_verbosity ) ;
2009-02-22 18:30:14 +01:00
#
# Timestamp each progress message, if true.
#
our $ timestamp ;
#
2009-10-06 00:43:29 +02:00
# Script (output) file handle
2009-02-22 18:30:14 +01:00
#
2009-10-06 00:43:29 +02:00
our $ script ;
2009-02-22 18:30:14 +01:00
#
2009-10-06 00:43:29 +02:00
# When 'true', writes to the script are enabled. Used to catch code emission between functions
2009-04-07 05:22:30 +02:00
#
2009-10-06 00:43:29 +02:00
our $ script_enabled ;
2009-04-07 05:22:30 +02:00
#
2009-02-22 18:30:14 +01:00
# True, if last line emitted is blank
#
our $ lastlineblank ;
#
# Tabs to indent the output
#
our $ indent1 ;
#
# Characters to indent the output
#
our $ indent2 ;
#
# Total indentation
#
our $ indent ;
#
2009-10-06 00:43:29 +02:00
# Script's Directory and File
2009-02-22 18:30:14 +01:00
#
our ( $ dir , $ file ) ;
#
# Temporary output file's name
#
our $ tempfile ;
#
# Misc Globals
#
our % globals ;
#
# From shorewall.conf file
#
our % config ;
#
2009-10-06 00:43:29 +02:00
# Config options and global settings that are to be copied to output script
2009-02-22 18:30:14 +01:00
#
2010-01-21 19:30:54 +01:00
our @ propagateconfig = qw/ DISABLE_IPV6 MODULESDIR MODULE_SUFFIX LOAD_HELPERS_ONLY SUBSYSLOCK / ;
2009-02-22 18:30:14 +01:00
#
2009-03-16 17:37:21 +01:00
# From parsing the capabilities file or detecting capabilities
2009-02-22 18:30:14 +01:00
#
our % capabilities ;
#
# Capabilities
#
our % capdesc = ( NAT_ENABLED = > 'NAT' ,
MANGLE_ENABLED = > 'Packet Mangling' ,
MULTIPORT = > 'Multi-port Match' ,
XMULTIPORT = > 'Extended Multi-port Match' ,
CONNTRACK_MATCH = > 'Connection Tracking Match' ,
2009-08-20 23:32:15 +02:00
OLD_CONNTRACK_MATCH = >
2009-02-22 18:30:14 +01:00
'Old conntrack match syntax' ,
2009-08-20 23:32:15 +02:00
NEW_CONNTRACK_MATCH = >
2009-02-22 18:30:14 +01:00
'Extended Connection Tracking Match' ,
USEPKTTYPE = > 'Packet Type Match' ,
POLICY_MATCH = > 'Policy Match' ,
PHYSDEV_MATCH = > 'Physdev Match' ,
PHYSDEV_BRIDGE = > 'Physdev-is-bridged support' ,
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' ,
OLD_IPP2P_MATCH = > 'Old IPP2P Match Syntax' ,
CLASSIFY_TARGET = > 'CLASSIFY Target' ,
ENHANCED_REJECT = > 'Extended Reject' ,
KLUDGEFREE = > 'Repeat match' ,
MARK = > 'MARK Target' ,
XMARK = > 'Extended Mark Target' ,
2010-01-13 02:01:20 +01:00
EXMARK = > 'Extended Mark Target 2' ,
2009-02-22 18:30:14 +01:00
MANGLE_FORWARD = > 'Mangle FORWARD Chain' ,
COMMENTS = > 'Comments' ,
ADDRTYPE = > 'Address Type Match' ,
TCPMSS_MATCH = > 'TCPMSS Match' ,
HASHLIMIT_MATCH = > 'Hashlimit Match' ,
NFQUEUE_TARGET = > 'NFQUEUE Target' ,
REALM_MATCH = > 'Realm Match' ,
HELPER_MATCH = > 'Helper Match' ,
CONNLIMIT_MATCH = > 'Connlimit Match' ,
TIME_MATCH = > 'Time Match' ,
GOTO_TARGET = > 'Goto Support' ,
2009-06-25 22:50:27 +02:00
LOG_TARGET = > 'LOG Target' ,
2009-04-12 17:22:19 +02:00
LOGMARK_TARGET = > 'LOGMARK Target' ,
2009-04-19 17:46:57 +02:00
IPMARK_TARGET = > 'IPMARK Target' ,
2009-08-15 17:35:54 +02:00
PERSISTENT_SNAT = > 'Persistent SNAT' ,
2009-09-23 22:56:31 +02:00
OLD_HL_MATCH = > 'Old Hash Limit Match' ,
2010-01-17 17:15:14 +01:00
TPROXY_TARGET = > 'TPROXY Target' ,
2009-02-22 18:30:14 +01:00
CAPVERSION = > 'Capability Version' ,
2009-12-19 21:42:39 +01:00
KERNELVERSION = > 'Kernel Version' ,
2009-02-22 18:30:14 +01:00
) ;
#
# 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 $ currentline ; # Current config file line image
our $ currentfile ; # File handle reference
our $ currentfilename ; # File NAME
our $ currentlinenumber ; # Line number
2009-10-06 00:43:29 +02:00
our $ perlscript ; # File Handle Reference to current temporary file being written by an in-line Perl script
our $ perlscriptname ; # Name of that file.
2009-02-22 18:30:14 +01:00
our @ tempfiles ; # Files that need unlinking at END
our $ first_entry ; # Message to output or function to call on first non-blank line of a file
2009-03-16 17:37:21 +01:00
our $ shorewall_dir ; # Shorewall Directory; if non-empty, search here first for files.
2009-02-22 18:30:14 +01:00
our $ debug ; # If true, use Carp to report errors with stack trace.
2009-03-16 17:37:21 +01:00
our $ family ; # Protocol family (4 or 6)
our $ toolname ; # Name of the tool to use (iptables or iptables6)
our $ toolNAME ; # Tool name in CAPS
our $ product ; # Name of product that will run the generated script
our $ Product ; # $product with initial cap.
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
our $ sillyname ; # Name of temporary filter chains for testing capabilities
our $ sillyname1 ;
our $ iptables ; # Path to iptables/ip6tables
2009-02-22 18:30:14 +01:00
use constant { MIN_VERBOSITY = > - 1 ,
MAX_VERBOSITY = > 2 ,
F_IPV4 = > 4 ,
F_IPV6 = > 6 ,
} ;
2009-03-16 17:37:21 +01:00
our % validlevels ; # Valid log levels.
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 ;
if ( $ family == F_IPV4 ) {
( $ product , $ Product , $ toolname , $ toolNAME ) = qw( shorewall Shorewall iptables IPTABLES ) ;
} else {
( $ product , $ Product , $ toolname , $ toolNAME ) = qw( shorewall6 Shorewall6 ip6tables IP6TABLES ) ;
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
2009-08-22 18:39:15 +02:00
$ verbosity = 0 ; # Verbosity setting. -1 = silent, 0 = almost silent, 1 = major progress messages only, 2 = all progress messages (very noisy)
2009-02-22 18:30:14 +01:00
$ log = undef ; # File reference for log file
2009-08-22 16:57:55 +02:00
$ log_verbosity = - 1 ; # Verbosity of log.
2009-02-22 18:30:14 +01:00
$ timestamp = '' ; # If true, we are to timestamp each progress message
2009-10-06 00:43:29 +02:00
$ script = 0 ; # Script (output) file Handle Reference
$ script_enabled = 0 ; # Writing to output file is disabled initially
2009-02-22 18:30:14 +01:00
$ lastlineblank = 0 ; # Avoid extra blank lines in the output
2009-03-16 17:37:21 +01:00
$ indent1 = '' ; # Current indentation tabs
$ indent2 = '' ; # Current indentation spaces
$ indent = '' ; # Current total indentation
2009-10-06 00:43:29 +02:00
( $ dir , $ file ) = ( '' , '' ) ; # Script's Directory and Filename
2009-02-22 18:30:14 +01:00
$ tempfile = '' ; # Temporary File Name
2010-01-25 19:50:49 +01:00
$ sillyname = '' ; # Temporary ipchain
2009-02-22 18:30:14 +01:00
#
# Misc Globals
#
% globals = ( SHAREDIR = > '/usr/share/shorewall' ,
2009-03-01 19:09:38 +01:00
SHAREDIRPL = > '/usr/share/shorewall/' ,
2009-02-22 18:30:14 +01:00
CONFDIR = > '/etc/shorewall' ,
LOGPARMS = > '' ,
TC_SCRIPT = > '' ,
EXPORT = > 0 ,
UNTRACKED = > 0 ,
2010-02-06 01:40:48 +01:00
VERSION = > "4.4.7" ,
2010-01-13 02:01:20 +01:00
CAPVERSION = > 40407 ,
2009-02-22 18:30:14 +01:00
) ;
#
# From shorewall.conf file
#
if ( $ family == F_IPV4 ) {
$ globals { PRODUCT } = 'shorewall' ;
% config =
( STARTUP_ENABLED = > undef ,
VERBOSITY = > undef ,
#
# Logging
#
LOGFILE = > undef ,
LOGFORMAT = > undef ,
LOGTAGONLY = > undef ,
LOGRATE = > undef ,
LOGBURST = > undef ,
LOGALLNEW = > undef ,
BLACKLIST_LOGLEVEL = > undef ,
2009-06-13 16:07:55 +02:00
RFC1918_LOG_LEVEL = > undef ,
2009-02-22 18:30:14 +01:00
MACLIST_LOG_LEVEL = > undef ,
TCP_FLAGS_LOG_LEVEL = > undef ,
SMURF_LOG_LEVEL = > undef ,
LOG_MARTIANS = > undef ,
LOG_VERBOSITY = > undef ,
STARTUP_LOG = > undef ,
#
# Location of Files
#
IPTABLES = > undef ,
2009-04-18 18:28:25 +02:00
IP = > undef ,
TC = > undef ,
2009-04-18 20:48:28 +02:00
IPSET = > undef ,
2009-02-22 18:30:14 +01:00
#
#PATH is inherited
#
PATH = > undef ,
SHOREWALL_SHELL = > undef ,
SUBSYSLOCK = > undef ,
MODULESDIR = > undef ,
#
#CONFIG_PATH is inherited
#
CONFIG_PATH = > undef ,
RESTOREFILE = > undef ,
IPSECFILE = > undef ,
LOCKFILE = > undef ,
#
# Default Actions/Macros
#
DROP_DEFAULT = > undef ,
REJECT_DEFAULT = > undef ,
ACCEPT_DEFAULT = > undef ,
QUEUE_DEFAULT = > undef ,
NFQUEUE_DEFAULT = > undef ,
#
# RSH/RCP Commands
#
RSH_COMMAND = > undef ,
RCP_COMMAND = > undef ,
#
# Firewall Options
#
BRIDGING = > undef ,
IP_FORWARDING = > undef ,
ADD_IP_ALIASES = > undef ,
ADD_SNAT_ALIASES = > undef ,
RETAIN_ALIASES = > undef ,
TC_ENABLED = > undef ,
TC_EXPERT = > undef ,
2010-01-13 02:01:20 +01:00
TC_PRIOMAP = > undef ,
2009-02-22 18:30:14 +01:00
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 ,
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 ,
SHOREWALL_COMPILER = > undef ,
EXPAND_POLICIES = > undef ,
KEEP_RT_TABLES = > undef ,
DELETE_THEN_ADD = > undef ,
MULTICAST = > undef ,
DONT_LOAD = > '' ,
AUTO_COMMENT = > undef ,
MANGLE_ENABLED = > undef ,
2009-06-13 16:07:55 +02:00
RFC1918_STRICT = > undef ,
2009-02-22 18:30:14 +01:00
NULL_ROUTE_RFC1918 = > undef ,
USE_DEFAULT_RT = > undef ,
RESTORE_DEFAULT_ROUTE = > undef ,
FAST_STOP = > undef ,
2009-03-31 19:31:23 +02:00
AUTOMAKE = > undef ,
2009-04-20 22:26:47 +02:00
WIDE_TC_MARKS = > undef ,
2009-10-20 22:24:17 +02:00
TRACK_PROVIDERS = > undef ,
2009-11-10 23:12:55 +01:00
ZONE2ZONE = > undef ,
2010-01-16 18:53:53 +01:00
ACCOUNTING = > undef ,
OPTIMIZE_ACCOUNTING = > undef ,
DYNAMIC_BLACKLIST = > undef ,
2010-01-21 18:58:04 +01:00
LOAD_HELPERS_ONLY = > undef ,
2009-02-22 18:30:14 +01:00
#
# Packet Disposition
#
MACLIST_DISPOSITION = > undef ,
TCP_FLAGS_DISPOSITION = > undef ,
BLACKLIST_DISPOSITION = > undef ,
2010-01-11 23:16:03 +01:00
#
# Mark Geometry
#
TC_BITS = > undef ,
PROVIDER_BITS = > undef ,
PROVIDER_OFFSET = > undef ,
MASK_BITS = > undef
2009-02-22 18:30:14 +01:00
) ;
% validlevels = ( DEBUG = > 7 ,
INFO = > 6 ,
NOTICE = > 5 ,
WARNING = > 4 ,
WARN = > 4 ,
ERR = > 3 ,
ERROR = > 3 ,
CRIT = > 2 ,
ALERT = > 1 ,
EMERG = > 0 ,
PANIC = > 0 ,
NONE = > '' ,
ULOG = > 'ULOG' ,
2009-04-12 17:22:19 +02:00
NFLOG = > 'NFLOG' ,
LOGMARK = > 'LOGMARK' ) ;
2009-02-22 18:30:14 +01:00
} else {
$ globals { SHAREDIR } = '/usr/share/shorewall6' ;
2009-08-20 23:32:15 +02:00
$ globals { CONFDIR } = '/etc/shorewall6' ;
2009-02-22 18:30:14 +01:00
$ globals { PRODUCT } = 'shorewall6' ;
% config =
( STARTUP_ENABLED = > undef ,
VERBOSITY = > undef ,
#
# Logging
#
LOGFILE = > undef ,
LOGFORMAT = > undef ,
LOGTAGONLY = > undef ,
LOGRATE = > undef ,
LOGBURST = > undef ,
LOGALLNEW = > undef ,
BLACKLIST_LOGLEVEL = > undef ,
TCP_FLAGS_LOG_LEVEL = > undef ,
SMURF_LOG_LEVEL = > undef ,
LOG_VERBOSITY = > undef ,
STARTUP_LOG = > undef ,
#
# Location of Files
#
IP6TABLES = > undef ,
2009-07-26 21:26:49 +02:00
IP = > undef ,
TC = > undef ,
IPSET = > undef ,
2009-02-22 18:30:14 +01:00
#
#PATH is inherited
#
PATH = > undef ,
SHOREWALL_SHELL = > undef ,
SUBSYSLOCK = > undef ,
MODULESDIR = > undef ,
#
#CONFIG_PATH is inherited
#
CONFIG_PATH = > undef ,
RESTOREFILE = > undef ,
LOCKFILE = > undef ,
#
# Default Actions/Macros
#
DROP_DEFAULT = > undef ,
REJECT_DEFAULT = > undef ,
ACCEPT_DEFAULT = > undef ,
QUEUE_DEFAULT = > undef ,
NFQUEUE_DEFAULT = > undef ,
#
# RSH/RCP Commands
#
RSH_COMMAND = > undef ,
RCP_COMMAND = > undef ,
#
# Firewall Options
#
IP_FORWARDING = > undef ,
TC_ENABLED = > undef ,
TC_EXPERT = > undef ,
2010-01-13 02:01:20 +01:00
TC_PRIOMAP = > undef ,
2009-02-22 18:30:14 +01:00
CLEAR_TC = > undef ,
MARK_IN_FORWARD_CHAIN = > undef ,
CLAMPMSS = > undef ,
MUTEX_TIMEOUT = > undef ,
ADMINISABSENTMINDED = > undef ,
BLACKLISTNEWONLY = > undef ,
MODULE_SUFFIX = > undef ,
MAPOLDACTIONS = > '' ,
FASTACCEPT = > undef ,
IMPLICIT_CONTINUE = > undef ,
HIGH_ROUTE_MARKS = > undef ,
OPTIMIZE = > undef ,
EXPORTPARAMS = > undef ,
EXPAND_POLICIES = > undef ,
KEEP_RT_TABLES = > undef ,
DELETE_THEN_ADD = > undef ,
MULTICAST = > undef ,
DONT_LOAD = > '' ,
AUTO_COMMENT = > undef ,
MANGLE_ENABLED = > undef ,
2009-03-31 19:31:23 +02:00
AUTOMAKE = > undef ,
2009-04-20 22:26:47 +02:00
WIDE_TC_MARKS = > undef ,
2009-10-20 22:24:17 +02:00
TRACK_PROVIDERS = > undef ,
2009-11-10 23:12:55 +01:00
ZONE2ZONE = > undef ,
2010-01-16 18:53:53 +01:00
ACCOUNTING = > undef ,
OPTIMIZE_ACCOUNTING = > undef ,
DYNAMIC_BLACKLIST = > undef ,
2010-01-21 18:58:04 +01:00
LOAD_HELPERS_ONLY = > undef ,
2009-02-22 18:30:14 +01:00
#
# Packet Disposition
#
TCP_FLAGS_DISPOSITION = > undef ,
BLACKLIST_DISPOSITION = > undef ,
2010-01-11 23:16:03 +01:00
#
# Mark Geometry
#
TC_BITS = > undef ,
PROVIDER_BITS = > undef ,
PROVIDER_OFFSET = > undef ,
MASK_BITS = > undef
2009-02-22 18:30:14 +01:00
) ;
% validlevels = ( DEBUG = > 7 ,
INFO = > 6 ,
NOTICE = > 5 ,
WARNING = > 4 ,
WARN = > 4 ,
ERR = > 3 ,
ERROR = > 3 ,
CRIT = > 2 ,
ALERT = > 1 ,
EMERG = > 0 ,
PANIC = > 0 ,
NONE = > '' ,
2009-04-12 17:22:19 +02:00
NFLOG = > 'NFLOG' ,
LOGMARK = > 'LOGMARK' ) ;
2009-09-23 22:56:31 +02:00
}
2009-02-22 18:30:14 +01:00
#
2010-01-25 16:56:16 +01:00
# From parsing the capabilities file or capabilities detection
2009-02-22 18:30:14 +01:00
#
% capabilities =
( NAT_ENABLED = > undef ,
MANGLE_ENABLED = > undef ,
MULTIPORT = > undef ,
XMULTIPORT = > undef ,
CONNTRACK_MATCH = > undef ,
NEW_CONNTRACK_MATCH = > undef ,
OLD_CONNTRACK_MATCH = > undef ,
USEPKTTYPE = > undef ,
POLICY_MATCH = > undef ,
PHYSDEV_MATCH = > undef ,
PHYSDEV_BRIDGE = > 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 ,
OLD_IPP2P_MATCH = > undef ,
CLASSIFY_TARGET = > undef ,
ENHANCED_REJECT = > undef ,
KLUDGEFREE = > undef ,
MARK = > undef ,
XMARK = > undef ,
2010-01-13 02:01:20 +01:00
EXMARK = > undef ,
2009-02-22 18:30:14 +01:00
MANGLE_FORWARD = > undef ,
COMMENTS = > undef ,
ADDRTYPE = > undef ,
TCPMSS_MATCH = > undef ,
HASHLIMIT_MATCH = > undef ,
NFQUEUE_TARGET = > undef ,
REALM_MATCH = > undef ,
HELPER_MATCH = > undef ,
CONNLIMIT_MATCH = > undef ,
TIME_MATCH = > undef ,
GOTO_TARGET = > undef ,
2009-04-12 17:22:19 +02:00
LOGMARK_TARGET = > undef ,
2009-04-19 17:46:57 +02:00
IPMARK_TARGET = > undef ,
2010-01-17 17:15:14 +01:00
TPROXY_TARGET = > undef ,
2009-06-25 22:50:27 +02:00
LOG_TARGET = > 1 , # Assume that we have it.
2009-08-15 17:35:54 +02:00
PERSISTENT_SNAT = > undef ,
2009-09-23 22:56:31 +02:00
OLD_HL_MATCH = > undef ,
2009-02-22 18:30:14 +01:00
CAPVERSION = > undef ,
2009-12-21 00:54:41 +01:00
KERNELVERSION = > undef ,
2009-02-22 18:30:14 +01:00
) ;
#
# Directories to search for configuration files
#
@ config_path = ( ) ;
#
# Stash away file references here when we encounter INCLUDE
#
@ includestack = ( ) ;
#
# Allow nested opens
#
@ openstack = ( ) ;
$ currentline = '' ; # Line image
$ currentfile = undef ; # File handle reference
$ currentfilename = '' ; # File NAME
$ currentlinenumber = 0 ; # Line number
$ first_entry = 0 ; # Message to output or function to call on first non-blank file entry
$ shorewall_dir = '' ; #Shorewall Directory
$ debug = 0 ;
}
INIT {
#
# These variables appear within single quotes in shorewall.conf -- add them to ENV
# so that read_a_line doesn't have to be smart enough to parse that usage.
#
for ( qw/root system command files destination/ ) {
$ ENV { $ _ } = '' unless exists $ ENV { $ _ } ;
}
}
my @ abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ) ;
#
# Issue a Warning Message
#
sub warning_message
{
my $ linenumber = $ currentlinenumber || 1 ;
my $ currentlineinfo = $ currentfile ? " : $currentfilename (line $linenumber)" : '' ;
our @ localtime ;
2009-08-31 19:41:08 +02:00
$| = 1 ; #Reset output buffering (flush any partially filled buffers).
2009-02-22 18:30:14 +01:00
if ( $ log ) {
@ localtime = localtime ;
printf $ log '%s %2d %02d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
}
if ( $ debug ) {
print STDERR longmess ( " WARNING: @_$currentlineinfo" ) ;
print $ log longmess ( " WARNING: @_$currentlineinfo\n" ) if $ log ;
} else {
print STDERR " WARNING: @_$currentlineinfo\n" ;
print $ log " WARNING: @_$currentlineinfo\n" if $ log ;
}
2009-08-31 19:41:08 +02:00
$| = 0 ; #Re-allow output buffering
2009-02-22 18:30:14 +01:00
}
2009-08-26 19:34:04 +02:00
sub cleanup () {
#
# Close files first in case we're running under Cygwin
#
2009-10-06 00:43:29 +02:00
close $ script , $ script = undef if $ script ;
close $ perlscript , $ perlscript = undef if $ perlscript ;
2009-08-30 17:05:10 +02:00
close $ log , $ log = undef if $ log ;
2009-08-26 19:34:04 +02:00
#
# Unlink temporary files
#
2009-08-31 18:08:49 +02:00
unlink ( $ tempfile ) , $ tempfile = undef if $ tempfile ;
2009-10-06 00:43:29 +02:00
unlink ( $ perlscriptname ) , $ perlscriptname = undef if $ perlscriptname ;
2009-08-31 18:08:49 +02:00
unlink ( @ tempfiles ) , @ tempfiles = ( ) if @ tempfiles ;
2010-01-25 19:50:49 +01:00
#
2010-01-26 00:59:31 +01:00
# Delete temporary chains
2010-01-25 19:50:49 +01:00
#
if ( $ sillyname ) {
2010-01-26 00:59:31 +01:00
#
# We went through determine_capabilities()
#
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -F $sillyname" ) ;
qt1 ( "$iptables -X $sillyname" ) ;
qt1 ( "$iptables -F $sillyname1" ) ;
qt1 ( "$iptables -X $sillyname1" ) ;
qt1 ( "$iptables -t mangle -F $sillyname" ) ;
qt1 ( "$iptables -t mangle -X $sillyname" ) ;
2010-01-26 00:59:31 +01:00
$ sillyname = '' ;
2010-01-25 19:50:49 +01:00
}
2009-08-26 19:34:04 +02:00
}
2009-02-22 18:30:14 +01:00
#
# Issue fatal error message and die
#
sub fatal_error {
my $ linenumber = $ currentlinenumber || 1 ;
my $ currentlineinfo = $ currentfile ? " : $currentfilename (line $linenumber)" : '' ;
2009-08-31 19:41:08 +02:00
$| = 1 ; #Reset output buffering (flush any partially filled buffers).
2009-02-22 18:30:14 +01:00
if ( $ log ) {
our @ localtime = localtime ;
printf $ log '%s %2d %02d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
if ( $ debug ) {
print $ log longmess ( " ERROR: @_$currentlineinfo\n" ) ;
} else {
print $ log " ERROR: @_$currentlineinfo\n" ;
}
close $ log ;
$ log = undef ;
}
2009-08-26 19:34:04 +02:00
cleanup ;
2009-02-22 18:30:14 +01:00
confess " ERROR: @_$currentlineinfo" if $ debug ;
die " ERROR: @_$currentlineinfo\n" ;
}
sub fatal_error1 {
$| = 1 ;
if ( $ log ) {
our @ localtime = localtime ;
printf $ log '%s %2d %02d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
if ( $ debug ) {
print $ log longmess ( " ERROR: @_\n" ) ;
} else {
print $ log " ERROR: @_\n" ;
}
close $ log ;
$ log = undef ;
}
2009-08-26 19:34:04 +02:00
cleanup ;
2009-02-22 18:30:14 +01:00
confess " ERROR: @_" if $ debug ;
die " ERROR: @_\n" ;
}
2009-03-09 22:45:18 +01:00
#
# C/C++-like assertion checker
#
2009-03-09 21:56:53 +01:00
sub assert ( $ ) {
unless ( $ _ [ 0 ] ) {
2009-03-09 22:45:30 +01:00
my @ caller0 = caller 0 ; # Where assert() was called
my @ caller1 = caller 1 ; # Who called assert()
2009-03-09 21:56:53 +01:00
2009-03-09 22:45:30 +01:00
fatal_error "Internal error in $caller1[3] at $caller0[1] line $caller0[2]" ;
2009-03-09 21:56:53 +01:00
}
}
2009-02-22 18:30:14 +01:00
#
# Convert value to decimal number
#
sub numeric_value ( $ ) {
my $ mark = lc $ _ [ 0 ] ;
2009-04-21 16:08:47 +02:00
my $ negative = ( $ mark =~ s/^-// ) ;
return undef unless $ mark =~ /^(0x[a-f0-9]+|0[0-7]*|[1-9]\d*)$/ ;
no warnings ;
$ mark = ( $ mark =~ /^0/ ? oct $ mark : $ mark ) ;
2009-04-20 22:26:47 +02:00
use warnings ;
2009-04-21 16:08:47 +02:00
$ negative ? - $ mark : $ mark ;
2009-02-22 18:30:14 +01:00
}
sub numeric_value1 ( $ ) {
2009-04-20 22:26:47 +02:00
no warnings ;
2009-02-22 18:30:14 +01:00
my $ val = numeric_value $ _ [ 0 ] ;
fatal_error "Invalid Number ($_[0])" unless defined $ val ;
$ val ;
2009-04-20 22:26:47 +02:00
use warnings ;
2009-02-22 18:30:14 +01:00
}
2009-04-23 21:43:57 +02:00
sub hex_value ( $ ) {
my $ val = lc $ _ [ 0 ] ;
2009-05-06 01:23:37 +02:00
return undef unless $ val =~ /^[a-fA-F0-9]+$/ ;
2009-04-23 21:43:57 +02:00
no warnings ;
oct '0x' . $ val ;
use warnings ;
}
2009-02-22 18:30:14 +01:00
#
# Return the argument expressed in Hex
#
sub in_hex ( $ ) {
sprintf '0x%x' , $ _ [ 0 ] ;
}
sub in_hex2 ( $ ) {
sprintf '0x%02x' , $ _ [ 0 ] ;
}
sub in_hex3 ( $ ) {
sprintf '0x%03x' , $ _ [ 0 ] ;
}
sub in_hex4 ( $ ) {
sprintf '0x%04x' , $ _ [ 0 ] ;
}
sub in_hex8 ( $ ) {
sprintf '0x%08x' , $ _ [ 0 ] ;
}
2009-04-23 21:43:57 +02:00
sub in_hexp ( $ ) {
sprintf '%x' , $ _ [ 0 ] ;
}
2009-02-22 18:30:14 +01:00
#
2009-10-06 00:43:29 +02:00
# Write the arguments to the script file (if any) with the current indentation.
2009-02-22 18:30:14 +01:00
#
# Replaces leading spaces with tabs as appropriate and suppresses consecutive blank lines.
#
sub emit {
2009-10-06 00:43:29 +02:00
assert ( $ script_enabled ) ;
2009-04-07 05:22:30 +02:00
2009-10-06 00:43:29 +02:00
if ( $ script ) {
2009-02-22 18:30:14 +01:00
#
# 'compile' as opposed to 'check'
#
for ( @ _ ) {
unless ( /^\s*$/ ) {
my $ line = $ _ ; # This copy is necessary because the actual arguments are almost always read-only.
$ line =~ s/^\n// if $ lastlineblank ;
$ line =~ s/^/$indent/gm if $ indent ;
$ line =~ s/ /\t/gm ;
2009-10-06 00:43:29 +02:00
print $ script "$line\n" ;
2009-02-22 18:30:14 +01:00
$ lastlineblank = ( substr ( $ line , - 1 , 1 ) eq "\n" ) ;
} else {
2009-10-06 00:43:29 +02:00
print $ script "\n" unless $ lastlineblank ;
2009-02-22 18:30:14 +01:00
$ lastlineblank = 1 ;
}
}
}
}
2010-01-11 23:16:03 +01:00
#
# Version of emit() that writes to standard out
#
sub emitstd {
for ( @ _ ) {
unless ( /^\s*$/ ) {
my $ line = $ _ ; # This copy is necessary because the actual arguments are almost always read-only.
$ line =~ s/^\n// if $ lastlineblank ;
$ line =~ s/^/$indent/gm if $ indent ;
$ line =~ s/ /\t/gm ;
print "$line\n" ;
$ lastlineblank = ( substr ( $ line , - 1 , 1 ) eq "\n" ) ;
} else {
print "\n" unless $ lastlineblank ;
$ lastlineblank = 1 ;
}
}
}
2009-02-22 18:30:14 +01:00
#
2009-10-06 00:43:29 +02:00
# Write passed message to the script with newline but no indentation.
2009-02-22 18:30:14 +01:00
#
sub emit_unindented ( $ ) {
2009-10-06 00:43:29 +02:00
assert ( $ script_enabled ) ;
2009-04-07 05:22:30 +02:00
2009-10-06 00:43:29 +02:00
print $ script "$_[0]\n" if $ script ;
2009-02-22 18:30:14 +01:00
}
#
# Write a progress_message2 command with surrounding blank lines to the output file.
#
sub save_progress_message ( $ ) {
2009-10-06 00:43:29 +02:00
emit "\nprogress_message2 @_\n" if $ script ;
2009-02-22 18:30:14 +01:00
}
#
# Write a progress_message command to the output file.
#
sub save_progress_message_short ( $ ) {
2009-10-06 00:43:29 +02:00
emit "progress_message $_[0]" if $ script ;
2009-02-22 18:30:14 +01:00
}
#
# Set $timestamp
#
sub set_timestamp ( $ ) {
$ timestamp = shift ;
}
#
2009-08-22 16:57:55 +02:00
# Set $verbosity
2009-02-22 18:30:14 +01:00
#
2009-08-22 16:57:55 +02:00
sub set_verbosity ( $ ) {
$ verbosity = shift ;
2009-02-22 18:30:14 +01:00
}
#
2009-08-22 16:57:55 +02:00
# Set $log and $log_verbosity
2009-02-22 18:30:14 +01:00
#
sub set_log ( $$ ) {
my ( $ l , $ v ) = @ _ ;
if ( defined $ v ) {
my $ value = numeric_value ( $ v ) ;
fatal_error "Invalid Log Verbosity ( $v )" unless defined ( $ value ) && ( $ value >= - 1 ) && ( $ value <= 2 ) ;
2009-08-22 16:57:55 +02:00
$ log_verbosity = $ value ;
2009-02-22 18:30:14 +01:00
}
2009-08-22 16:57:55 +02:00
if ( $ l && $ log_verbosity >= 0 ) {
2009-02-22 18:30:14 +01:00
unless ( open $ log , '>>' , $ l ) {
2009-08-20 23:32:15 +02:00
$ log = undef ;
2009-02-22 18:30:14 +01:00
fatal_error "Unable to open STARTUP_LOG ($l) for writing: $!" ;
}
} else {
2009-08-22 16:57:55 +02:00
$ log_verbosity = - 1 ;
2009-02-22 18:30:14 +01:00
}
}
sub close_log () {
close $ log , $ log = undef if $ log ;
}
#
# Set $command, $doing and $done
#
sub set_command ( $$$ ) {
( $ command , $ doing , $ done ) = @ _ ;
}
#
# Print the current TOD to STDOUT.
#
sub timestamp () {
our @ localtime = localtime ;
printf '%02d:%02d:%02d ' , @ localtime [ 2 , 1 , 0 ] ;
}
#
2009-08-22 16:57:55 +02:00
# Write a message if $verbosity >= 2
2009-02-22 18:30:14 +01:00
#
sub progress_message {
my $ havelocaltime = 0 ;
2009-08-22 16:57:55 +02:00
if ( $ verbosity > 1 || $ log_verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
my $ line = "@_" ;
my $ leading = $ line =~ /^(\s+)/ ? $ 1 : '' ;
$ line =~ s/\s+/ /g ;
2009-08-22 16:57:55 +02:00
if ( $ verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
timestamp , $ havelocaltime = 1 if $ timestamp ;
#
# We use this function to display messages containing raw config file images which may contains tabs (including multiple tabs in succession).
# The following makes such messages look more readable and uniform
#
print "${leading}${line}\n" ;
}
2009-08-22 16:57:55 +02:00
if ( $ log_verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
our @ localtime ;
2009-08-20 23:32:15 +02:00
@ localtime = localtime unless $ havelocaltime ;
2009-02-22 18:30:14 +01:00
printf $ log '%s %2d %2d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
print $ log "${leading}${line}\n" ;
}
}
}
sub progress_message_nocompress {
my $ havelocaltime = 0 ;
2009-08-22 16:57:55 +02:00
if ( $ verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
timestamp , $ havelocaltime = 1 if $ timestamp ;
print "@_\n" ;
}
2009-08-22 16:57:55 +02:00
if ( $ log_verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
our @ localtime ;
2009-08-20 23:32:15 +02:00
@ localtime = localtime unless $ havelocaltime ;
2009-02-22 18:30:14 +01:00
printf $ log '%s %2d %2d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
print $ log "@_\n" ;
}
}
#
2009-08-22 16:57:55 +02:00
# Write a message if $verbosity >= 1
2009-02-22 18:30:14 +01:00
#
sub progress_message2 {
my $ havelocaltime = 0 ;
2009-08-22 16:57:55 +02:00
if ( $ verbosity > 0 ) {
2009-02-22 18:30:14 +01:00
timestamp , $ havelocaltime = 1 if $ timestamp ;
print "@_\n" ;
}
2009-08-22 16:57:55 +02:00
if ( $ log_verbosity > 0 ) {
2009-02-22 18:30:14 +01:00
our @ localtime ;
2009-08-20 23:32:15 +02:00
@ localtime = localtime unless $ havelocaltime ;
2009-02-22 18:30:14 +01:00
printf $ log '%s %2d %02d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
print $ log "@_\n" ;
}
}
#
2009-08-22 16:57:55 +02:00
# Write a message if $verbosity >= 0
2009-02-22 18:30:14 +01:00
#
sub progress_message3 {
my $ havelocaltime = 0 ;
2009-08-22 16:57:55 +02:00
if ( $ verbosity >= 0 ) {
2009-02-22 18:30:14 +01:00
timestamp , $ havelocaltime = 1 if $ timestamp ;
print "@_\n" ;
}
2009-08-22 16:57:55 +02:00
if ( $ log_verbosity >= 0 ) {
2009-02-22 18:30:14 +01:00
our @ localtime ;
@ localtime = localtime unless $ havelocaltime ;
printf $ log '%s %2d %02d:%02d:%02d ' , $ abbr [ $ localtime [ 4 ] ] , @ localtime [ 3 , 2 , 1 , 0 ] ;
print $ log "@_\n" ;
}
}
#
# Push/Pop Indent
#
sub push_indent () {
if ( $ indent2 ) {
$ indent2 = '' ;
$ indent = $ indent1 = $ indent1 . "\t" ;
} else {
$ indent2 = ' ' ;
$ indent = $ indent1 . $ indent2 ;
}
}
sub pop_indent () {
if ( $ indent2 ) {
$ indent2 = '' ;
$ indent = $ indent1 ;
} else {
$ indent1 = substr ( $ indent1 , 0 , - 1 ) ;
$ indent2 = ' ' ;
$ indent = $ indent1 . $ indent2 ;
}
}
#
2009-10-06 00:43:29 +02:00
# Functions for copying files into the script
2009-02-22 18:30:14 +01:00
#
sub copy ( $ ) {
2009-10-06 00:43:29 +02:00
assert ( $ script_enabled ) ;
2009-04-07 05:22:30 +02:00
2009-10-06 00:43:29 +02:00
if ( $ script ) {
2009-02-22 18:30:14 +01:00
my $ file = $ _ [ 0 ] ;
open IF , $ file or fatal_error "Unable to open $file: $!" ;
while ( <IF> ) {
chomp ;
if ( /^\s*$/ ) {
2009-10-06 00:43:29 +02:00
print $ script "\n" unless $ lastlineblank ;
2009-02-22 18:30:14 +01:00
$ lastlineblank = 1 ;
} else {
if ( $ indent ) {
2009-08-20 23:32:15 +02:00
s/^(\s*)/$indent1$1$indent2/ ;
2009-02-22 18:30:14 +01:00
s/ /\t/ if $ indent2 ;
}
2009-10-06 00:43:29 +02:00
print $ script $ _ ;
print $ script "\n" ;
2009-02-22 18:30:14 +01:00
$ lastlineblank = 0 ;
}
}
close IF ;
}
}
#
# This one handles line continuation and 'here documents'
sub copy1 ( $ ) {
2009-10-06 00:43:29 +02:00
assert ( $ script_enabled ) ;
2009-04-07 05:22:30 +02:00
2009-06-29 17:14:53 +02:00
my $ result = 0 ;
2009-10-06 00:43:29 +02:00
if ( $ script ) {
2009-02-22 18:30:14 +01:00
my $ file = $ _ [ 0 ] ;
open IF , $ file or fatal_error "Unable to open $file: $!" ;
my ( $ do_indent , $ here_documents ) = ( 1 , '' ) ;
while ( <IF> ) {
chomp ;
if ( /^${here_documents}\s*$/ ) {
2009-10-06 00:43:29 +02:00
print $ script $ here_documents if $ here_documents ;
print $ script "\n" ;
2009-02-22 18:30:14 +01:00
$ do_indent = 1 ;
$ here_documents = '' ;
next ;
}
if ( $ do_indent && /.*<<\s*([^ ]+)s*(.*)/ ) {
$ here_documents = $ 1 ;
s/^(\s*)/$indent1$1$indent2/ ;
s/ /\t/ if $ indent2 ;
$ do_indent = 0 ;
2009-10-06 00:43:29 +02:00
print $ script $ _ ;
print $ script "\n" ;
2009-06-29 17:14:53 +02:00
$ result = 1 ;
2009-02-22 18:30:14 +01:00
next ;
}
if ( $ indent && $ do_indent ) {
s/^(\s*)/$indent1$1$indent2/ ;
s/ /\t/ if $ indent2 ;
}
2009-10-06 00:43:29 +02:00
print $ script $ _ ;
print $ script "\n" ;
2009-02-22 18:30:14 +01:00
$ do_indent = ! ( $ here_documents || /\\$/ ) ;
2009-06-29 17:14:53 +02:00
$ result = 1 unless $ result || /^\s*$/ || /^\s*#/ ;
2009-02-22 18:30:14 +01:00
}
close IF ;
}
2009-06-19 23:39:45 +02:00
$ lastlineblank = 0 ;
2009-06-29 17:14:53 +02:00
$ result ;
2009-02-22 18:30:14 +01:00
}
#
2009-10-06 00:43:29 +02:00
# Create the temporary script file -- the passed file name is the name of the final file.
2009-02-22 18:30:14 +01:00
# We create a temporary file in the same directory so that we can use rename to finalize it.
#
2009-10-06 00:43:29 +02:00
sub create_temp_script ( $$ ) {
my ( $ scriptfile , $ export ) = @ _ ;
2009-02-22 18:30:14 +01:00
my $ suffix ;
2009-10-06 00:43:29 +02:00
if ( $ scriptfile eq '-' ) {
2009-08-22 16:57:55 +02:00
$ verbosity = - 1 ;
2009-10-06 00:43:29 +02:00
$ script = undef ;
open ( $ script , '>&STDOUT' ) or fatal_error "Open of STDOUT failed" ;
2009-04-21 18:41:23 +02:00
$ file = '-' ;
return 1 ;
}
2009-02-22 18:30:14 +01:00
eval {
2009-10-06 00:43:29 +02:00
( $ file , $ dir , $ suffix ) = fileparse ( $ scriptfile ) ;
2009-02-22 18:30:14 +01:00
} ;
2009-08-26 19:34:04 +02:00
cleanup , die if $@ ;
2009-02-22 18:30:14 +01:00
fatal_error "$dir is a Symbolic Link" if - l $ dir ;
fatal_error "Directory $dir does not exist" unless - d _ ;
fatal_error "Directory $dir is not writable" unless - w _ ;
2009-10-06 00:43:29 +02:00
fatal_error "$scriptfile is a Symbolic Link" if - l $ scriptfile ;
fatal_error "$scriptfile is a Directory" if - d _ ;
fatal_error "$scriptfile exists and is not a compiled script" if - e _ && ! - x _ ;
2009-02-22 18:30:14 +01:00
fatal_error "An exported \u$globals{PRODUCT} compiled script may not be named '$globals{PRODUCT}'" if $ export && "$file" eq $ globals { PRODUCT } && $ suffix eq '' ;
eval {
$ dir = abs_path $ dir unless $ dir =~ m | ^ /|; # Work around http:/ /rt.cpan.org/ Public /Bug/ Display . html ? id = 13851
2009-10-06 00:43:29 +02:00
( $ script , $ tempfile ) = tempfile ( 'tempfileXXXX' , DIR = > $ dir ) ;
2009-02-22 18:30:14 +01:00
} ;
fatal_error "Unable to create temporary file in directory $dir" if $@ ;
$ file = "$file.$suffix" if $ suffix ;
$ dir . = '/' unless substr ( $ dir , - 1 , 1 ) eq '/' ;
$ file = $ dir . $ file ;
}
#
2009-10-06 00:43:29 +02:00
# Finalize the script file
2009-02-22 18:30:14 +01:00
#
2009-10-06 00:43:29 +02:00
sub finalize_script ( $ ) {
2009-02-22 18:30:14 +01:00
my $ export = $ _ [ 0 ] ;
2009-10-06 00:43:29 +02:00
close $ script ;
$ script = 0 ;
2009-04-21 18:41:23 +02:00
if ( $ file ne '-' ) {
rename $ tempfile , $ file or fatal_error "Cannot Rename $tempfile to $file: $!" ;
chmod 0700 , $ file or fatal_error "Cannot secure $file for execute access" ;
progress_message3 "Shorewall configuration compiled to $file" unless $ export ;
}
2009-02-22 18:30:14 +01:00
}
#
# Create the temporary aux config file.
#
sub create_temp_aux_config () {
eval {
2009-10-06 00:43:29 +02:00
( $ script , $ tempfile ) = tempfile ( 'tempfileXXXX' , DIR = > $ dir ) ;
2009-02-22 18:30:14 +01:00
} ;
2009-08-26 19:34:04 +02:00
cleanup , die if $@ ;
2009-02-22 18:30:14 +01:00
}
#
# Finalize the aux config file.
#
sub finalize_aux_config () {
2009-10-06 00:43:29 +02:00
close $ script ;
$ script = 0 ;
2009-02-22 18:30:14 +01:00
rename $ tempfile , "$file.conf" or fatal_error "Cannot Rename $tempfile to $file.conf: $!" ;
progress_message3 "Shorewall configuration compiled to $file" ;
}
2009-04-07 05:22:30 +02:00
#
2009-10-06 00:43:29 +02:00
# Enable writes to the script file
2009-04-07 05:22:30 +02:00
#
2009-10-06 00:43:29 +02:00
sub enable_script () {
$ script_enabled = 1 ;
2009-04-07 05:22:30 +02:00
}
#
2009-10-06 00:43:29 +02:00
# Disable writes to the script file
2009-04-07 05:22:30 +02:00
#
2009-10-06 00:43:29 +02:00
sub disable_script () {
$ script_enabled = 0 ;
2009-04-07 05:22:30 +02:00
}
2009-02-22 18:30:14 +01:00
#
# Set $config{CONFIG_PATH}
#
sub set_config_path ( $ ) {
$ config { CONFIG_PATH } = shift ;
}
#
# Set $debug
#
sub set_debug ( $ ) {
$ debug = shift ;
}
#
# Search the CONFIG_PATH for the passed file
#
sub find_file ($)
{
my $ filename = $ _ [ 0 ] ;
return $ filename if $ filename =~ '/' ;
my $ directory ;
for $ directory ( @ config_path ) {
my $ file = "$directory$filename" ;
return $ file if - f $ file ;
}
"$globals{CONFDIR}/$filename" ;
}
sub split_list ( $$ ) {
my ( $ list , $ type ) = @ _ ;
fatal_error "Invalid $type list ($list)" if $ list =~ /^,|,$|,,|!,|,!$/ ;
split /,/ , $ list ;
}
sub split_list1 ( $$ ) {
my ( $ list , $ type ) = @ _ ;
fatal_error "Invalid $type list ($list)" if $ list =~ /^,|,$|,,|!,|,!$/ ;
my @ list1 = split /,/ , $ list ;
my @ list2 ;
my $ element = '' ;
for ( @ list1 ) {
2009-02-26 18:12:55 +01:00
my $ count ;
if ( ( $ count = tr /(/ ( / ) > 0 ) {
fatal_error "Invalid $type list ($list)" if $ element || $ count > 1 ;
if ( ( $ count = tr /)/ ) / ) > 0 ) {
fatal_error "Invalid $type list ($list)" if $ count > 1 ;
2009-02-26 17:53:33 +01:00
push @ list2 , $ _ ;
} else {
$ element = $ _ ;
}
2009-02-26 18:12:55 +01:00
} elsif ( ( $ count = tr /)/ ) / ) > 0 ) {
fatal_error "Invalid $type list ($list)" unless $ element && $ count == 1 ;
2009-02-22 18:30:14 +01:00
push @ list2 , join ',' , $ element , $ _ ;
$ element = '' ;
} elsif ( $ element ) {
$ element = join ',' , $ element , $ _ ;
} else {
push @ list2 , $ _ ;
}
}
@ list2 ;
}
#
# Pre-process a line from a configuration file.
# ensure that it has an appropriate number of columns.
# supply '-' in omitted trailing columns.
#
sub split_line ( $$$ ) {
my ( $ mincolumns , $ maxcolumns , $ description ) = @ _ ;
fatal_error "Shorewall Configuration file entries may not contain single quotes, double quotes, single back quotes or backslashes" if $ currentline =~ /["'`\\]/ ;
fatal_error "Non-ASCII gunk in file" if $ currentline =~ /[^\s[:print:]]/ ;
my @ line = split ( ' ' , $ currentline ) ;
my $ line = @ line ;
fatal_error "Invalid $description entry (too many columns)" if $ line > $ maxcolumns ;
$ line - - while $ line > 0 && $ line [ $ line - 1 ] eq '-' ;
fatal_error "Invalid $description entry (too few columns)" if $ line < $ mincolumns ;
push @ line , '-' while @ line < $ maxcolumns ;
@ line ;
}
#
# Version of 'split_line' used on files with exceptions
#
sub split_line1 ( $$$;$ ) {
my ( $ mincolumns , $ maxcolumns , $ description , $ nopad ) = @ _ ;
fatal_error "Shorewall Configuration file entries may not contain double quotes, single back quotes or backslashes" if $ currentline =~ /["`\\]/ ;
my @ line = split ( ' ' , $ currentline ) ;
$ nopad = { COMMENT = > 0 } unless $ nopad ;
my $ first = $ line [ 0 ] ;
my $ columns = $ nopad - > { $ first } ;
if ( defined $ columns ) {
fatal_error "Invalid $first entry" if $ columns && @ line != $ columns ;
return @ line
}
fatal_error "Shorewall Configuration file entries may not contain single quotes" if $ currentline =~ /'/ ;
my $ line = @ line ;
fatal_error "Invalid $description entry (too many columns)" if $ line > $ maxcolumns ;
$ line - - while $ line > 0 && $ line [ $ line - 1 ] eq '-' ;
fatal_error "Invalid $description entry (too few columns)" if $ line < $ mincolumns ;
push @ line , '-' while @ line < $ maxcolumns ;
@ line ;
}
#
# Open a file, setting $currentfile. Returns the file's absolute pathname if the file
# exists, is non-empty and was successfully opened. Terminates with a fatal error
# if the file exists, is non-empty, but the open fails.
#
sub do_open_file ( $ ) {
my $ fname = $ _ [ 0 ] ;
open $ currentfile , '<' , $ fname or fatal_error "Unable to open $fname: $!" ;
$ currentlinenumber = 0 ;
$ currentfilename = $ fname ;
}
sub open_file ( $ ) {
my $ fname = find_file $ _ [ 0 ] ;
2009-03-09 21:56:53 +01:00
assert ( ! defined $ currentfile ) ;
2009-02-22 18:30:14 +01:00
- f $ fname && - s _ ? do_open_file $ fname : '' ;
}
#
# Pop the include stack
#
sub pop_include () {
my $ arrayref = pop @ includestack ;
if ( $ arrayref ) {
( $ currentfile , $ currentfilename , $ currentlinenumber ) = @$ arrayref ;
} else {
$ currentfile = undef ;
}
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
#
# This function is normally called below in read_a_line() when EOF is reached. Clients of the
# module may also call the function to close the file before EOF
#
sub close_file () {
if ( $ currentfile ) {
my $ result = close $ currentfile ;
pop_include ;
fatal_error "SHELL Script failed" unless $ result ;
$ first_entry = 0 ;
}
}
#
# The following two functions allow module clients to nest opens. This happens frequently
# in the Actions module.
#
sub push_open ( $ ) {
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
my @ a = @ includestack ;
push @ openstack , \ @ a ;
@ includestack = ( ) ;
$ currentfile = undef ;
open_file ( $ _ [ 0 ] ) ;
}
sub pop_open () {
@ includestack = @ { pop @ openstack } ;
pop_include ;
}
2009-08-23 19:43:01 +02:00
#
# This function is called by in-line PERL to generate a line of input for the current file.
# If the in-line PERL returns an indication of success, then the generated lines will be
# processed as regular file input.
#
2009-02-22 18:30:14 +01:00
sub shorewall {
2009-10-06 00:43:29 +02:00
unless ( $ perlscript ) {
2009-02-22 18:30:14 +01:00
fatal_error "shorewall() may not be called in this context" unless $ currentfile ;
$ dir || = '/tmp/' ;
eval {
2009-10-06 00:43:29 +02:00
( $ perlscript , $ perlscriptname ) = tempfile ( 'perlscriptXXXX' , DIR = > $ dir ) ;
2009-02-22 18:30:14 +01:00
} ;
fatal_error "Unable to create temporary file in directory $dir" if $@ ;
}
2009-10-06 00:43:29 +02:00
print $ perlscript "@_\n" ;
2009-02-22 18:30:14 +01:00
}
#
2009-08-20 23:32:15 +02:00
# We don't announce that we are checking/compiling a file until we determine that the file contains
2009-02-22 18:30:14 +01:00
# at least one non-blank, non-commentary line.
#
# The argument to this function may be either a scalar or a function reference. When the first
2009-08-20 23:32:15 +02:00
# non-blank/non-commentary line is reached:
2009-02-22 18:30:14 +01:00
#
# - if a function reference was passed to first_entry(), that function is called
# - otherwise, the argument to first_entry() is passed to progress_message2().
#
# We do this processing in read_a_line() rather than in the higher-level routines because
# Embedded Shell/Perl scripts are processed out of read_a_line(). If we were to defer announcement
2009-08-20 23:32:15 +02:00
# until we get back to the caller of read_a_line(), we could issue error messages about parsing and
2009-02-22 18:30:14 +01:00
# running scripts in the file before we'd even indicated that we are processing it.
#
sub first_entry ( $ ) {
$ first_entry = $ _ [ 0 ] ;
my $ reftype = reftype $ first_entry ;
if ( $ reftype ) {
fatal_error "Invalid argument to first_entry()" unless $ reftype eq 'CODE' ;
}
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
sub embedded_shell ( $ ) {
my $ multiline = shift ;
fatal_error "INCLUDEs nested too deeply" if @ includestack >= 4 ;
my ( $ command , $ linenumber ) = ( "/bin/sh -c '$currentline" , $ currentlinenumber ) ;
if ( $ multiline ) {
#
# Multi-line script
#
fatal_error "Invalid BEGIN SHELL directive" unless $ currentline =~ /^\s*$/ ;
$ command . = "\n" ;
my $ last = 0 ;
while ( <$currentfile> ) {
$ currentlinenumber + + ;
last if $ last = s/^\s*END(\s+SHELL)?\s*;?// ;
$ command . = $ _ ;
}
fatal_error ( "Missing END SHELL" ) unless $ last ;
fatal_error ( "Invalid END SHELL directive" ) unless /^\s*$/ ;
}
$ command . = q( ' ) ;
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
$ currentfile = undef ;
open $ currentfile , '-|' , $ command or fatal_error qq( Shell Command failed ) ;
$ currentfilename = "SHELL\@$currentfilename:$currentlinenumber" ;
$ currentline = '' ;
$ currentlinenumber = 0 ;
}
sub embedded_perl ( $ ) {
my $ multiline = shift ;
2009-08-20 23:32:15 +02:00
my ( $ command , $ linenumber ) = ( qq( package Shorewall::User;\nno strict;\nuse Shorewall::Config qw/shorewall/;\n# line $currentlinenumber "$currentfilename"\n$currentline ) , $ currentlinenumber ) ;
2009-02-22 18:30:14 +01:00
if ( $ multiline ) {
#
# Multi-line script
#
fatal_error "Invalid BEGIN PERL directive" unless $ currentline =~ /^\s*$/ ;
$ command . = "\n" ;
my $ last = 0 ;
while ( <$currentfile> ) {
$ currentlinenumber + + ;
last if $ last = s/^\s*END(\s+PERL)?\s*;?// ;
$ command . = $ _ ;
}
fatal_error ( "Missing END PERL" ) unless $ last ;
fatal_error ( "Invalid END PERL directive" ) unless /^\s*$/ ;
}
unless ( my $ return = eval $ command ) {
if ( $@ ) {
#
# Perl found the script offensive or the script itself died
#
$@ =~ s/, <\$currentfile> line \d+//g ;
fatal_error1 "$@" ;
}
unless ( defined $ return ) {
2009-08-20 23:32:15 +02:00
fatal_error "Perl Script failed: $!" if $! ;
2009-02-22 18:30:14 +01:00
fatal_error "Perl Script failed" ;
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
fatal_error "Perl Script Returned False" ;
}
2009-10-06 00:43:29 +02:00
if ( $ perlscript ) {
2009-02-22 18:30:14 +01:00
fatal_error "INCLUDEs nested too deeply" if @ includestack >= 4 ;
2009-10-06 00:43:29 +02:00
close $ perlscript or assert ( 0 ) ;
2009-02-22 18:30:14 +01:00
2009-10-06 00:43:29 +02:00
$ perlscript = undef ;
2009-02-22 18:30:14 +01:00
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
$ currentfile = undef ;
2009-10-06 00:43:29 +02:00
open $ currentfile , '<' , $ perlscriptname or fatal_error "Unable to open Perl Script $perlscriptname" ;
2009-02-22 18:30:14 +01:00
2009-10-06 00:43:29 +02:00
push @ tempfiles , $ perlscriptname unless unlink $ perlscriptname ; #unlink fails on Cygwin
2009-02-22 18:30:14 +01:00
2009-10-06 00:43:29 +02:00
$ perlscriptname = '' ;
2009-02-22 18:30:14 +01:00
$ currentfilename = "PERL\@$currentfilename:$linenumber" ;
$ currentline = '' ;
$ currentlinenumber = 0 ;
}
}
#
# Read a line from the current include stack.
#
# - Ignore blank or comment-only lines.
# - Remove trailing comments.
# - Handle Line Continuation
# - Handle embedded SHELL and PERL scripts
# - Expand shell variables from $ENV.
# - Handle INCLUDE <filename>
#
sub read_a_line () {
while ( $ currentfile ) {
$ currentline = '' ;
$ currentlinenumber = 0 ;
while ( <$currentfile> ) {
$ currentlinenumber = $. unless $ currentlinenumber ;
chomp ;
#
2009-03-27 17:55:51 +01:00
# Suppress leading whitespace in certain continuation lines
#
s/^\s*// if $ currentline =~ /[,:]$/ ;
#
2009-09-07 01:17:22 +02:00
# If this isn't a continued line, remove trailing comments. Note that
# the result may now end in '\'.
#
s/\s*#.*$// unless /\\$/ ;
#
2009-02-22 18:30:14 +01:00
# Continuation
#
chop $ currentline , next if substr ( ( $ currentline . = $ _ ) , - 1 , 1 ) eq '\\' ;
#
2009-09-13 18:20:32 +02:00
# Now remove concatinated comments
2009-02-22 18:30:14 +01:00
#
$ currentline =~ s/#.*$// ;
#
# Ignore ( concatenated ) Blank Lines
#
$ currentline = '' , $ currentlinenumber = 0 , next if $ currentline =~ /^\s*$/ ;
#
# Line not blank -- Handle any first-entry message/capabilities check
#
if ( $ first_entry ) {
2009-08-23 19:43:01 +02:00
#
# $first_entry can contain either a function reference or a message. If it
# contains a reference, call the function -- otherwise issue the message
#
2009-02-22 18:30:14 +01:00
reftype ( $ first_entry ) ? $ first_entry - > ( ) : progress_message2 ( $ first_entry ) ;
$ first_entry = 0 ;
}
#
# Must check for shell/perl before doing variable expansion
#
if ( $ currentline =~ s/^\s*(BEGIN\s+)?SHELL\s*;?// ) {
embedded_shell ( $ 1 ) ;
} elsif ( $ currentline =~ s/^\s*(BEGIN\s+)?PERL\s*\;?// ) {
embedded_perl ( $ 1 ) ;
} else {
my $ count = 0 ;
#
# Expand Shell Variables using %ENV
#
# $1 $2 $3 - $4
while ( $ currentline =~ m ( ^(.*?) \ $( { ) ? ( [ a - zA - Z ] \ w * ) ( ? ( 2 ) } ) ( . * ) $ ) x ) {
my $ val = $ ENV { $ 3 } ;
unless ( defined $ val ) {
fatal_error "Undefined shell variable (\$$3)" unless exists $ ENV { $ 3 } ;
$ val = '' ;
}
$ currentline = join ( '' , $ 1 , $ val , $ 4 ) ;
fatal_error "Variable Expansion Loop" if + + $ count > 100 ;
}
if ( $ currentline =~ /^\s*INCLUDE\s/ ) {
my @ line = split ' ' , $ currentline ;
fatal_error "Invalid INCLUDE command" if @ line != 2 ;
fatal_error "INCLUDEs/Scripts nested too deeply" if @ includestack >= 4 ;
my $ filename = find_file $ line [ 1 ] ;
fatal_error "INCLUDE file $filename not found" unless - f $ filename ;
fatal_error "Directory ($filename) not allowed in INCLUDE" if - d _ ;
if ( - s _ ) {
push @ includestack , [ $ currentfile , $ currentfilename , $ currentlinenumber ] ;
$ currentfile = undef ;
do_open_file $ filename ;
} else {
$ currentlinenumber = 0 ;
}
$ currentline = '' ;
} else {
return 1 ;
}
}
}
close_file ;
}
}
#
# Simple version of the above. Doesn't do line concatenation, shell variable expansion or INCLUDE processing
#
sub read_a_line1 () {
while ( $ currentfile ) {
while ( $ currentline = <$currentfile> ) {
next if $ currentline =~ /^\s*#/ ;
chomp $ currentline ;
next if $ currentline =~ /^\s*$/ ;
$ currentline =~ s/#.*$// ; # Remove Trailing Comments
fatal_error "Non-ASCII gunk in file" if $ currentline =~ /[^\s[:print:]]/ ;
$ currentlinenumber = $. ;
return 1 ;
}
close_file ;
}
}
#
# Provide the passed default value for the passed configuration variable
#
sub default ( $$ ) {
my ( $ var , $ val ) = @ _ ;
$ config { $ var } = $ val unless defined $ config { $ var } && $ config { $ var } ne '' ;
}
#
# Provide a default value for a yes/no configuration variable.
#
sub default_yes_no ( $$ ) {
my ( $ var , $ val ) = @ _ ;
my $ curval = "\L$config{$var}" ;
if ( defined $ curval && $ curval ne '' ) {
if ( $ curval eq 'no' ) {
$ config { $ var } = '' ;
} else {
fatal_error "Invalid value for $var ($val)" unless $ curval eq 'yes' ;
}
} else {
$ config { $ var } = $ val ;
}
}
sub default_yes_no_ipv4 ( $$ ) {
my ( $ var , $ val ) = @ _ ;
default_yes_no ( $ var , $ val ) ;
warning_message "$var=Yes is ignored for IPv6" if $ family == F_IPV6 && $ config { $ var } ;
}
2010-01-11 23:16:03 +01:00
sub numeric_option ( $$$ ) {
my ( $ option , $ default , $ min ) = @ _ ;
my $ value = $ config { $ option } ;
my $ val = $ default ;
if ( defined $ value && $ value ne '' ) {
$ val = numeric_value $ value ;
fatal_error "Invalid value ($value) for '$option'" unless defined $ val && $ val <= 32 ;
}
$ val = $ min if $ val < $ min ;
$ config { $ option } = $ val ;
}
sub make_mask ( $ ) {
0xffffffff >> ( 32 - $ _ [ 0 ] ) ;
}
2009-02-22 18:30:14 +01:00
my @ suffixes = qw( group range threshold nlgroup cprange qthreshold ) ;
#
# Validate a log level -- Drop the trailing '!' and translate to numeric value if appropriate"
#
sub level_error ( $ ) {
fatal_error "Invalid log level ($_[0])" ;
}
sub validate_level ( $ ) {
my $ rawlevel = $ _ [ 0 ] ;
my $ level = uc $ rawlevel ;
if ( defined $ level && $ level ne '' ) {
$ level =~ s/!$// ;
my $ value = $ validlevels { $ level } ;
2009-06-25 22:50:27 +02:00
if ( defined $ value ) {
require_capability ( 'LOG_TARGET' , 'A log level other than NONE' , 's' ) unless $ value eq '' ;
return $ value ;
}
if ( $ level =~ /^[0-7]$/ ) {
require_capability ( 'LOG_TARGET' , 'A log level other than NONE' , 's' ) ;
return $ level ;
}
2009-02-22 18:30:14 +01:00
if ( $ level =~ /^(NFLOG|ULOG)[(](.*)[)]$/ ) {
my $ olevel = $ 1 ;
my @ options = split /,/ , $ 2 ;
my $ prefix = lc $ olevel ;
my $ index = $ prefix eq 'ulog' ? 3 : 0 ;
level_error ( $ level ) if @ options > 3 ;
for ( @ options ) {
if ( defined $ _ and $ _ ne '' ) {
level_error ( $ level ) unless /^\d+/ ;
$ olevel . = " --${prefix}-$suffixes[$index] $_" ;
}
$ index + + ;
}
2009-06-25 22:50:27 +02:00
require_capability ( 'LOG_TARGET' , 'A log level other than NONE' , 's' ) ;
2009-02-22 18:30:14 +01:00
return $ olevel ;
}
if ( $ level =~ /^NFLOG --/ or $ level =~ /^ULOG --/ ) {
2009-06-25 22:50:27 +02:00
require_capability ( 'LOG_TARGET' , 'A log level other than NONE' , 's' ) ;
2009-02-22 18:30:14 +01:00
return $ rawlevel ;
}
2009-04-12 17:22:19 +02:00
if ( $ level eq 'LOGMARK' ) {
2009-06-25 22:50:27 +02:00
require_capability ( 'LOG_TARGET' , 'A log level other than NONE' , 's' ) ;
2009-04-12 17:22:19 +02:00
require_capability ( 'LOGMARK_TARGET' , 'LOGMARK' , 's' ) ;
return 'LOGMARK' ;
}
2009-02-22 18:30:14 +01:00
level_error ( $ rawlevel ) ;
}
'' ;
}
#
# Validate a log level and supply default
#
sub default_log_level ( $$ ) {
my ( $ level , $ default ) = @ _ ;
my $ value = $ config { $ level } ;
unless ( defined $ value && $ value ne '' ) {
$ config { $ level } = $ default ;
} else {
$ config { $ level } = validate_level $ value ;
}
}
#
# Check a tri-valued variable
#
sub check_trivalue ( $$ ) {
my ( $ var , $ default ) = @ _ ;
my $ val = "\L$config{$var}" ;
if ( defined $ val ) {
if ( $ val eq 'yes' || $ val eq 'on' ) {
$ config { $ var } = 'on' ;
} elsif ( $ val eq 'no' || $ val eq 'off' ) {
$ config { $ var } = 'off' ;
} elsif ( $ val eq 'keep' ) {
$ config { $ var } = '' ;
} elsif ( $ val eq '' ) {
$ config { $ var } = $ default
} else {
fatal_error "Invalid value ($val) for $var" ;
}
} else {
$ config { var } = $ default
}
}
#
# Produce a report of the detected capabilities
#
sub report_capability ( $ ) {
my $ cap = $ _ [ 0 ] ;
print " $capdesc{$cap}: " ;
2009-12-19 21:42:39 +01:00
if ( $ cap eq 'CAPVERSION' || $ cap eq 'KERNELVERSION' ) {
my $ version = $ capabilities { $ cap } ;
2009-02-22 18:30:14 +01:00
printf "%d.%d.%d\n" , int ( $ version / 10000 ) , int ( ( $version % 10000 ) / 100 ) , int ( $ version % 100 ) ;
} else {
print $ capabilities { $ cap } ? "Available\n" : "Not Available\n" ;
}
}
sub report_capabilities () {
2009-08-22 16:57:55 +02:00
if ( $ verbosity > 1 ) {
2009-02-22 18:30:14 +01:00
print "Shorewall has detected the following capabilities:\n" ;
for my $ cap ( sort { $ capdesc { $ a } cmp $ capdesc { $ b } } keys % capabilities ) {
report_capability $ cap ;
}
}
}
#
# Search the current PATH for the passed executable
#
sub which ( $ ) {
my $ prog = $ _ [ 0 ] ;
for ( split /:/ , $ config { PATH } ) {
return "$_/$prog" if - x "$_/$prog" ;
}
'' ;
}
#
# Load the kernel modules defined in the 'modules' file.
#
sub load_kernel_modules ( ) {
my $ moduleloader = which ( 'modprobe' ) || ( which '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:/lib/modules/$uname/extra:/lib/modules/$uname/extra/ipset" ;
}
my @ moduledirectories = split /:/ , $ modulesdir ;
2010-01-23 01:44:45 +01:00
if ( $ moduleloader && open_file ( $ config { LOAD_HELPERS_ONLY } ? 'helpers' : 'modules' ) ) {
2009-02-22 18:30:14 +01:00
my % loadedmodules ;
$ loadedmodules { $ _ } + + for split_list ( $ config { DONT_LOAD } , 'module' ) ;
progress_message "Loading Modules..." ;
open LSMOD , '-|' , 'lsmod' or fatal_error "Can't run lsmod" ;
while ( <LSMOD> ) {
my $ module = ( split ( /\s+/ , $ _ , 2 ) ) [ 0 ] ;
$ loadedmodules { $ module } + + unless $ module eq 'Module'
}
close LSMOD ;
2009-12-07 22:51:08 +01:00
$ config { MODULE_SUFFIX } = 'o gz ko o.gz ko.gz' unless $ config { MODULE_SUFFIX } ;
2009-02-22 18:30:14 +01:00
my @ suffixes = split /\s+/ , $ config { MODULE_SUFFIX } ;
while ( read_a_line ) {
fatal_error "Invalid modules file entry" unless ( $ currentline =~ /^loadmodule\s+([a-zA-Z]\w*)\s*(.*)$/ ) ;
my ( $ module , $ arguments ) = ( $ 1 , $ 2 ) ;
unless ( $ loadedmodules { $ module } ) {
for my $ directory ( @ moduledirectories ) {
for my $ suffix ( @ suffixes ) {
my $ modulefile = "$directory/$module.$suffix" ;
if ( - f $ modulefile ) {
if ( $ moduleloader eq 'insmod' ) {
system ( "insmod $modulefile $arguments" ) ;
} else {
system ( "modprobe $module $arguments" ) ;
}
$ loadedmodules { $ module } = 1 ;
}
}
}
}
}
}
}
#
# Q[uie]t version of system(). Returns true for success
#
sub qt ( $ ) {
system ( "@_ > /dev/null 2>&1" ) == 0 ;
}
sub qt1 ( $ ) {
1 while system ( "@_ > /dev/null 2>&1" ) == 4 ;
$? == 0 ;
}
2009-12-19 21:42:39 +01:00
#
# Get the current kernel version
#
sub determine_kernelversion () {
my $ kernelversion = `uname -r` ;
if ( $ kernelversion =~ /^(\d+)\.(\d+).(\d+)/ ) {
$ capabilities { KERNELVERSION } = sprintf "%d%02d%02d" , $ 1 , $ 2 , $ 3 ;
} else {
2010-01-06 17:26:13 +01:00
fatal_error "Unrecognized Kernel Version Format ($kernelversion)" ;
2009-12-19 21:42:39 +01:00
}
}
2009-02-22 18:30:14 +01:00
#
2010-01-29 19:38:22 +01:00
# Capability Reporting and detection.
2009-02-22 18:30:14 +01:00
#
2010-01-29 19:38:22 +01:00
sub have_capability ( $ ) ;
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Nat_Enabled () {
$ family == F_IPV4 ? qt1 ( "$iptables -t nat -L -n" ) : '' ;
}
2009-08-15 17:35:54 +02:00
2010-01-25 19:50:49 +01:00
sub Persistent_Snat () {
have_capability 'NAT_ENABLED' || return '' ;
2009-02-22 18:30:14 +01:00
2010-01-26 00:59:31 +01:00
my $ result = '' ;
2010-01-25 19:50:49 +01:00
if ( qt1 ( "$iptables -t nat -N $sillyname" ) ) {
2010-01-26 00:59:31 +01:00
$ result = qt1 ( "$iptables -t nat -A $sillyname -j SNAT --to-source 1.2.3.4 --persistent" ) ;
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -t nat -F $sillyname" ) ;
qt1 ( "$iptables -t nat -X $sillyname" ) ;
2010-01-26 00:59:31 +01:00
2010-01-25 19:50:49 +01:00
}
2010-01-26 00:59:31 +01:00
$ result ;
2010-01-25 19:50:49 +01:00
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Mangle_Enabled () {
if ( qt1 ( "$iptables -t mangle -L -n" ) ) {
system ( "$iptables -t mangle -N $sillyname" ) == 0 || fatal_error "Cannot Create Mangle chain $sillyname" ;
}
}
2009-03-28 20:21:36 +01:00
2010-01-25 19:50:49 +01:00
sub Conntrack_Match () {
2009-02-22 18:30:14 +01:00
if ( $ family == F_IPV4 ) {
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -A $sillyname -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT" ) ;
2009-02-22 18:30:14 +01:00
} else {
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -A $sillyname -m conntrack --ctorigdst ::1 -j ACCEPT" ) ;
2009-02-22 18:30:14 +01:00
}
2010-01-25 19:50:49 +01:00
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub New_Conntrack_Match () {
have_capability 'CONNTRACK_MATCH' && qt1 ( "$iptables -A $sillyname -m conntrack -p tcp --ctorigdstport 22 -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Old_Conntrack_Match () {
! qt1 ( "$iptables -A $sillyname -m conntrack ! --ctorigdst 1.2.3.4" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Multiport () {
qt1 ( "$iptables -A $sillyname -p tcp -m multiport --dports 21,22 -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Kludgefree1 () {
have_capability 'MULTIPORT' && qt1 ( "$iptables -A $sillyname -p tcp -m multiport --sports 60 -m multiport --dports 99 -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Kludgefree2 () {
have_capability 'PHYSDEV_MATCH' && qt1 ( "$iptables -A $sillyname -m physdev --physdev-in eth0 -m physdev --physdev-out eth0 -j ACCEPT" ) ;
}
sub Kludgefree3 () {
2009-02-22 18:30:14 +01:00
if ( $ family == F_IPV4 ) {
2010-01-25 19:50:49 +01:00
qt1 ( "$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" ) ;
2009-02-22 18:30:14 +01:00
} else {
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -A $sillyname -m iprange --src-range ::1-::2 -m iprange --dst-range 192.168.1.5-192.168.1.124 -j ACCEPT" ) ;
2009-02-22 18:30:14 +01:00
}
2010-01-25 19:50:49 +01:00
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Kludgefree () {
Kludgefree1 || Kludgefree2 || Kludgefree3 ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Xmultiport () {
qt1 ( "$iptables -A $sillyname -p tcp -m multiport --dports 21:22 -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Policy_Match () {
qt1 ( "$iptables -A $sillyname -m policy --pol ipsec --mode tunnel --dir in -j ACCEPT" ) ;
}
sub Physdev_Match () {
qt1 ( "$iptables -A $sillyname -m physdev --physdev-in eth0 -j ACCEPT" ) ;
}
sub Physdev_Bridge () {
qt1 ( "$iptables -A $sillyname -m physdev --physdev-is-bridged --physdev-in eth0 --physdev-out eth1 -j ACCEPT" ) ;
}
sub IPRange_Match () {
if ( $ family == F_IPV4 ) {
qt1 ( "$iptables -A $sillyname -m iprange --src-range 192.168.1.5-192.168.1.124 -j ACCEPT" ) ;
2009-12-07 22:51:08 +01:00
} else {
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -A $sillyname -m iprange --src-range ::1-::2 -j ACCEPT" ) ;
2009-12-07 22:51:08 +01:00
}
2010-01-25 19:50:49 +01:00
}
sub Recent_Match () {
qt1 ( "$iptables -A $sillyname -m recent --update -j ACCEPT" ) ;
}
sub Owner_Match () {
qt1 ( "$iptables -A $sillyname -m owner --uid-owner 0 -j ACCEPT" ) ;
}
sub Connmark_Match () {
qt1 ( "$iptables -A $sillyname -m connmark --mark 2 -j ACCEPT" ) ;
}
sub Xconnmark_Match () {
have_capability 'CONNMARK_MATCH' && qt1 ( "$iptables -A $sillyname -m connmark --mark 2/0xFF -j ACCEPT" ) ;
}
2009-12-07 22:51:08 +01:00
2010-01-25 19:50:49 +01:00
sub Ipp2p_Match () {
qt1 ( "$iptables -A $sillyname -p tcp -m ipp2p --edk -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Old_Ipp2p_Match () {
qt1 ( "$iptables -A $sillyname -p tcp -m ipp2p --ipp2p -j ACCEPT" ) if $ capabilities { IPP2P_MATCH } ;
}
2009-09-23 22:56:31 +02:00
2010-01-25 19:50:49 +01:00
sub Length_Match () {
qt1 ( "$iptables -A $sillyname -m length --length 10:20 -j ACCEPT" ) ;
}
sub Enhanced_Reject () {
if ( $ family == F_IPV6 ) {
qt1 ( "$iptables -A $sillyname -j REJECT --reject-with icmp6-adm-prohibited" ) ;
2009-09-23 22:56:31 +02:00
} else {
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -A $sillyname -j REJECT --reject-with icmp-host-prohibited" ) ;
2009-09-23 22:56:31 +02:00
}
2010-01-25 19:50:49 +01:00
}
2009-09-23 22:56:31 +02:00
2010-01-25 19:50:49 +01:00
sub Comments () {
qt1 ( qq( $iptables -A $sillyname -j ACCEPT -m comment --comment "This is a comment" ) ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Hashlimit_Match () {
2010-01-27 21:53:31 +01:00
have_capability 'OLD_HL_MATCH' || qt1 ( "$iptables -A $sillyname -m hashlimit --hashlimit-upto 3/min --hashlimit-burst 3 --hashlimit-name $sillyname --hashlimit-mode srcip -j ACCEPT" ) ;
2010-01-25 19:50:49 +01:00
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Old_Hashlimit_Match () {
2010-01-28 02:52:27 +01:00
qt1 ( "$iptables -A $sillyname -m hashlimit --hashlimit 3/min --hashlimit-burst 3 --hashlimit-name $sillyname --hashlimit-mode srcip -j ACCEPT" ) ;
2010-01-25 19:50:49 +01:00
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Mark () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -A $sillyname -j MARK --set-mark 1" ) ;
}
2009-08-20 23:32:15 +02:00
2010-01-25 19:50:49 +01:00
sub Xmark () {
have_capability 'MARK' && qt1 ( "$iptables -t mangle -A $sillyname -j MARK --and-mark 0xFF" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Exmark () {
have_capability 'MARK' && qt1 ( "$iptables -t mangle -A $sillyname -j MARK --set-mark 1/0xFF" ) ;
}
sub Connmark () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Xconnmark () {
have_capability 'XCONNMARK_MATCH' && have_capability 'XMARK' && qt1 ( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark --mask 0xFF" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Classify_Target () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -A $sillyname -j CLASSIFY --set-class 1:1" ) ;
}
sub IPMark_Target () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -A $sillyname -j IPMARK --addr src" ) ;
}
sub Tproxy_Target () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -A $sillyname -p tcp -j TPROXY --on-port 0 --tproxy-mark 1" ) ;
}
sub Mangle_Forward () {
have_capability 'MANGLE_ENABLED' && qt1 ( "$iptables -t mangle -L FORWARD -n" ) ;
}
sub Raw_Table () {
qt1 ( "$iptables -t raw -L -n" ) ;
}
sub IPSet_Match () {
my $ ipset = $ config { IPSET } || 'ipset' ;
my $ result = 0 ;
2009-02-22 18:30:14 +01:00
2009-05-28 15:42:47 +02:00
$ ipset = which $ ipset unless $ ipset =~ '//' ;
2009-04-18 18:28:25 +02:00
if ( $ ipset && - x $ ipset ) {
qt ( "$ipset -X $sillyname" ) ;
if ( qt ( "$ipset -N $sillyname iphash" ) ) {
2009-02-22 18:30:14 +01:00
if ( qt1 ( "$iptables -A $sillyname -m set --set $sillyname src -j ACCEPT" ) ) {
qt1 ( "$iptables -D $sillyname -m set --set $sillyname src -j ACCEPT" ) ;
2010-01-25 19:50:49 +01:00
$ result = 1 ;
2009-02-22 18:30:14 +01:00
}
2009-04-18 18:28:25 +02:00
qt ( "$ipset -X $sillyname" ) ;
2009-02-22 18:30:14 +01:00
}
}
2010-01-25 19:50:49 +01:00
$ result ;
}
sub Usepkttype () {
qt1 ( "$iptables -A $sillyname -m pkttype --pkt-type broadcast -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Addrtype () {
qt1 ( "$iptables -A $sillyname -m addrtype --src-type BROADCAST -j ACCEPT" ) ;
}
2009-02-22 18:30:14 +01:00
2010-01-25 19:50:49 +01:00
sub Tcpmss_Match () {
qt1 ( "$iptables -A $sillyname -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1000:1500 -j ACCEPT" ) ;
}
2009-12-19 21:42:39 +01:00
2010-01-25 19:50:49 +01:00
sub Nfqueue_Target () {
qt1 ( "$iptables -A $sillyname -j NFQUEUE --queue-num 4" ) ;
2009-02-22 18:30:14 +01:00
}
2010-01-25 19:50:49 +01:00
sub Realm_Match () {
qt1 ( "$iptables -A $sillyname -m realm --realm 1" ) ;
}
sub Helper_Match () {
qt1 ( "$iptables -A $sillyname -m helper --helper \"ftp\"" ) ;
}
sub Connlimit_Match () {
qt1 ( "$iptables -A $sillyname -m connlimit --connlimit-above 8" ) ;
}
sub Time_Match () {
qt1 ( "$iptables -A $sillyname -m time --timestart 11:00" ) ;
}
sub Goto_Target () {
qt1 ( "$iptables -A $sillyname -g $sillyname1" ) ;
}
sub Log_Target () {
qt1 ( "$iptables -A $sillyname -j LOG" ) ;
}
sub Logmark_Target () {
qt1 ( "$iptables -A $sillyname -j LOGMARK" ) ;
2010-01-25 16:56:16 +01:00
}
2010-01-29 01:39:45 +01:00
our % detect_capability =
2010-01-29 22:09:53 +01:00
( ADDRTYPE = > \ & Addrtype ,
CLASSIFY_TARGET = > \ & Classify_Target ,
COMMENTS = > \ & Comments ,
CONNLIMIT_MATCH = > \ & Connlimit_Match ,
2010-01-29 01:39:45 +01:00
CONNMARK = > \ & Connmark ,
CONNMARK_MATCH = > \ & Connmark_Match ,
2010-01-29 22:09:53 +01:00
CONNTRACK_MATCH = > \ & Conntrack_Match ,
2010-01-29 01:39:45 +01:00
ENHANCED_REJECT = > \ & Enhanced_Reject ,
EXMARK = > \ & Exmark ,
2010-01-29 22:09:53 +01:00
GOTO_TARGET = > \ & Goto_Target ,
2010-01-29 01:39:45 +01:00
HASHLIMIT_MATCH = > \ & Hashlimit_Match ,
HELPER_MATCH = > \ & Helper_Match ,
IPMARK_TARGET = > \ & IPMark_Target ,
2010-01-29 22:09:53 +01:00
IPP2P_MATCH = > \ & Ipp2p_Match ,
IPRANGE_MATCH = > \ & IPRange_Match ,
IPSET_MATCH = > \ & IPSet_Match ,
KLUDGEFREE = > \ & Kludgefree ,
LENGTH_MATCH = > \ & Length_Match ,
LOGMARK_TARGET = > \ & Logmark_Target ,
2010-01-29 01:39:45 +01:00
LOG_TARGET = > \ & Log_Target ,
2010-01-29 22:09:53 +01:00
MANGLE_ENABLED = > \ & Mangle_Enabled ,
MANGLE_FORWARD = > \ & Mangle_Forward ,
MARK = > \ & Mark ,
MULTIPORT = > \ & Multiport ,
NAT_ENABLED = > \ & Nat_Enabled ,
NEW_CONNTRACK_MATCH = > \ & New_Conntrack_Match ,
NFQUEUE_TARGET = > \ & Nfqueue_Target ,
OLD_CONNTRACK_MATCH = > \ & Old_Conntrack_Match ,
2010-01-29 01:39:45 +01:00
OLD_HL_MATCH = > \ & Old_Hashlimit_Match ,
2010-01-29 22:09:53 +01:00
OLD_IPP2P_MATCH = > \ & Old_Ipp2p_Match ,
OWNER_MATCH = > \ & Owner_Match ,
PERSISTENT_SNAT = > \ & Persistent_Snat ,
PHYSDEV_BRIDGE = > \ & Physdev_Bridge ,
PHYSDEV_MATCH = > \ & Physdev_Match ,
POLICY_MATCH = > \ & Policy_Match ,
RAW_TABLE = > \ & Raw_Table ,
REALM_MATCH = > \ & Realm_Match ,
RECENT_MATCH = > \ & Recent_Match ,
TCPMSS_MATCH = > \ & Tcpmss_Match ,
TIME_MATCH = > \ & Time_Match ,
TPROXY_TARGET = > \ & Tproxy_Target ,
USEPKTTYPE = > \ & Usepkttype ,
XCONNMARK_MATCH = > \ & Xconnmark_Match ,
XCONNMARK = > \ & Xconnmark ,
XMARK = > \ & Xmark ,
XMULTIPORT = > \ & Xmultiport ,
2010-01-29 01:39:45 +01:00
) ;
sub detect_capability ( $ ) {
my $ capability = shift ;
2010-01-29 19:38:22 +01:00
my $ function = $ detect_capability { $ capability } ;
assert ( ( reftype ( $ function ) || '' ) eq 'CODE' ) ;
$ function - > ( ) ;
}
#
# Report the passed capability
#
sub have_capability ( $ ) {
my $ capability = shift ;
our % detect_capability ;
$ capabilities { $ capability } = detect_capability ( $ capability ) unless defined $ capabilities { $ capability } ;
$ capabilities { $ capability } ;
2010-01-29 01:39:45 +01:00
}
2010-01-25 16:56:16 +01:00
#
2010-01-25 19:50:49 +01:00
# Determine which optional facilities are supported by iptables/netfilter
2010-01-25 16:56:16 +01:00
#
2010-01-25 19:50:49 +01:00
sub determine_capabilities ( $ ) {
$ iptables = $ _ [ 0 ] ;
my $ pid = $$ ;
2010-01-29 19:38:22 +01:00
$ capabilities { CAPVERSION } = $ globals { CAPVERSION } ;
determine_kernelversion ;
2010-01-25 19:50:49 +01:00
$ sillyname = "fooX$pid" ;
$ sillyname1 = "foo1X$pid" ;
qt1 ( "$iptables -N $sillyname" ) ;
qt1 ( "$iptables -N $sillyname1" ) ;
fatal_error 'Your kernel/iptables do not include state match support. No version of Shorewall will run on this system'
unless qt1 ( "$iptables -A $sillyname -m state --state ESTABLISHED,RELATED -j ACCEPT" ) ;
unless ( $ config { LOAD_HELPERS_ONLY } ) {
2010-01-29 19:38:22 +01:00
#
# Using 'detect_capability()' is a bit less efficient than calling the individual detection
# functions but it ensures that %detect_capability is initialized properly.
#
$ capabilities { NAT_ENABLED } = detect_capability ( 'NAT_ENABLED' ) ;
$ capabilities { PERSISTENT_SNAT } = detect_capability ( 'PERSISTENT_SNAT' ) ;
$ capabilities { MANGLE_ENABLED } = detect_capability ( 'MANGLE_ENABLED' ) ;
2010-01-25 19:50:49 +01:00
2010-01-29 19:38:22 +01:00
if ( $ capabilities { CONNTRACK_MATCH } = detect_capability ( 'CONNTRACK_MATCH' ) ) {
$ capabilities { NEW_CONNTRACK_MATCH } = detect_capability ( 'NEW_CONNTRACK_MATCH' ) ;
$ capabilities { OLD_CONNTRACK_MATCH } = detect_capability ( 'OLD_CONNTRACK_MATCH' ) ;
2010-01-25 19:50:49 +01:00
} else {
$ capabilities { NEW_CONNTRACK_MATCH } = '' ;
$ capabilities { OLD_CONNTRACK_MATCH } = '' ;
}
2010-01-29 19:38:22 +01:00
if ( $ capabilities { MULTIPORT } = detect_capability ( 'MULTIPORT' ) ) {
2010-01-25 19:50:49 +01:00
$ capabilities { KLUDGEFREE } = Kludgefree1 ;
}
2010-01-29 19:38:22 +01:00
$ capabilities { XMULTIPORT } = detect_capability ( 'XMULTIPORT' ) ;
$ capabilities { POLICY_MATCH } = detect_capability ( 'POLICY_MATCH' ) ;
2010-01-25 19:50:49 +01:00
2010-01-29 19:38:22 +01:00
if ( $ capabilities { PHYSDEV_MATCH } = detect_capability ( 'PHYSDEV_MATCH' ) ) {
$ capabilities { PHYSDEV_BRIDGE } = detect_capability ( 'PHYSDEV_BRIDGE' ) ;
2010-01-25 19:50:49 +01:00
$ capabilities { KLUDGEFREE } || = Kludgefree2 ;
} else {
$ capabilities { PHYSDEV_BRIDGE } = '' ;
}
2010-01-29 19:38:22 +01:00
if ( $ capabilities { IPRANGE_MATCH } = detect_capability ( 'IPRANGE_MATCH' ) ) {
2010-01-25 19:50:49 +01:00
$ capabilities { KLUDGEFREE } || = Kludgefree3 ;
}
2010-01-29 19:38:22 +01:00
$ capabilities { RECENT_MATCH } = detect_capability ( 'RECENT_MATCH' ) ;
$ capabilities { OWNER_MATCH } = detect_capability ( 'OWNER_MATCH' ) ;
$ capabilities { CONNMARK_MATCH } = detect_capability ( 'CONNMARK_MATCH' ) ;
$ capabilities { XCONNMARK_MATCH } = detect_capability ( 'XCONNMARK_MATCH' ) ;
$ capabilities { IPP2P_MATCH } = detect_capability ( 'IPP2P_MATCH' ) ;
$ capabilities { OLD_IPP2P_MATCH } = detect_capability ( 'OLD_IPP2P_MATCH' ) ;
$ capabilities { LENGTH_MATCH } = detect_capability ( 'LENGTH_MATCH' ) ;
$ capabilities { ENHANCED_REJECT } = detect_capability ( 'ENHANCED_REJECT' ) ;
$ capabilities { COMMENTS } = detect_capability ( 'COMMENTS' ) ;
$ capabilities { OLD_HL_MATCH } = detect_capability ( 'OLD_HL_MATCH' ) ;
$ capabilities { HASHLIMIT_MATCH } = detect_capability ( 'HASHLIMIT_MATCH' ) ;
$ capabilities { MARK } = detect_capability ( 'MARK' ) ;
$ capabilities { XMARK } = detect_capability ( 'XMARK' ) ;
$ capabilities { EXMARK } = detect_capability ( 'EXMARK' ) ;
$ capabilities { CONNMARK } = detect_capability ( 'CONNMARK' ) ;
$ capabilities { XCONNMARK } = detect_capability ( 'XCONNMARK' ) ;
$ capabilities { CLASSIFY_TARGET } = detect_capability ( 'CLASSIFY_TARGET' ) ;
$ capabilities { IPMARK_TARGET } = detect_capability ( 'IPMARK_TARGET' ) ;
$ capabilities { TPROXY_TARGET } = detect_capability ( 'TPROXY_TARGET' ) ;
2010-01-25 19:50:49 +01:00
if ( $ capabilities { MANGLE_ENABLED } ) {
qt1 ( "$iptables -t mangle -F $sillyname" ) ;
qt1 ( "$iptables -t mangle -X $sillyname" ) ;
}
2010-01-29 19:38:22 +01:00
$ capabilities { MANGLE_FORWARD } = detect_capability ( 'MANGLE_FORWARD' ) ;
$ capabilities { RAW_TABLE } = detect_capability ( 'RAW_TABLE' ) ;
$ capabilities { IPSET_MATCH } = detect_capability ( 'IPSET_MATCH' ) ;
$ capabilities { USEPKTTYPE } = detect_capability ( 'USEPKTTYPE' ) ;
$ capabilities { ADDRTYPE } = detect_capability ( 'ADDRTYPE' ) ;
$ capabilities { TCPMSS_MATCH } = detect_capability ( 'TCPMSS_MATCH' ) ;
$ capabilities { NFQUEUE_TARGET } = detect_capability ( 'NFQUEUE_TARGET' ) ;
$ capabilities { REALM_MATCH } = detect_capability ( 'REALM_MATCH' ) ;
$ capabilities { HELPER_MATCH } = detect_capability ( 'HELPER_MATCH' ) ;
$ capabilities { CONNLIMIT_MATCH } = detect_capability ( 'CONNLIMIT_MATCH' ) ;
$ capabilities { TIME_MATCH } = detect_capability ( 'TIME_MATCH' ) ;
$ capabilities { GOTO_TARGET } = detect_capability ( 'GOTO_TARGET' ) ;
$ capabilities { LOG_TARGET } = detect_capability ( 'LOG_TARGET' ) ;
$ capabilities { LOGMARK_TARGET } = detect_capability ( 'LOGMARK_TARGET' ) ;
2010-01-25 19:50:49 +01:00
qt1 ( "$iptables -F $sillyname" ) ;
qt1 ( "$iptables -X $sillyname" ) ;
qt1 ( "$iptables -F $sillyname1" ) ;
qt1 ( "$iptables -X $sillyname1" ) ;
$ sillyname = $ sillyname1 = undef ;
}
2010-01-25 16:56:16 +01:00
}
2009-02-22 18:30:14 +01:00
#
# Require the passed capability
#
sub require_capability ( $$$ ) {
my ( $ capability , $ description , $ singular ) = @ _ ;
2010-01-25 19:50:49 +01:00
fatal_error "$description require${singular} $capdesc{$capability} in your kernel and iptables" unless have_capability $ capability ;
2009-02-22 18:30:14 +01:00
}
#
# Set default config path
#
sub ensure_config_path () {
my $ f = "$globals{SHAREDIR}/configpath" ;
$ globals { CONFDIR } = "/usr/share/$product/configfiles/" if $> != 0 ;
unless ( $ config { CONFIG_PATH } ) {
fatal_error "$f does not exist" unless - f $ f ;
open_file $ f ;
$ ENV { CONFDIR } = $ globals { CONFDIR } ;
while ( read_a_line ) {
if ( $ currentline =~ /^\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" ;
}
}
fatal_error "CONFIG_PATH not found in $f" unless $ config { CONFIG_PATH } ;
}
@ config_path = split /:/ , $ config { CONFIG_PATH } ;
for ( @ config_path ) {
$ _ . = '/' unless m | / $| ;
}
if ( $ shorewall_dir ) {
$ shorewall_dir = getcwd if $ shorewall_dir =~ m | ^ ( \ . / * ) + $| ;
$ shorewall_dir . = '/' unless $ shorewall_dir =~ m | / $| ;
unshift @ config_path , $ shorewall_dir if $ shorewall_dir ne $ config_path [ 0 ] ;
$ config { CONFIG_PATH } = join ':' , @ config_path ;
}
}
#
# Set $shorewall_dir
#
sub set_shorewall_dir ( $ ) {
$ shorewall_dir = shift ;
ensure_config_path ;
}
#
# Small functions called by get_configuration. We separate them so profiling is more useful
#
sub process_shorewall_conf () {
my $ file = find_file "$product.conf" ;
if ( - f $ file ) {
if ( - r _ ) {
open_file $ file ;
while ( read_a_line ) {
if ( $ currentline =~ /^\s*([a-zA-Z]\w*)=(.*?)\s*$/ ) {
my ( $ var , $ val ) = ( $ 1 , $ 2 ) ;
unless ( exists $ config { $ var } ) {
warning_message "Unknown configuration option ($var) ignored" ;
next ;
}
$ config { $ var } = ( $ val =~ /\"([^\"]*)\"$/ ? $ 1 : $ val ) ;
} else {
fatal_error "Unrecognized entry" ;
}
}
} else {
fatal_error "Cannot read $file (Hint: Are you root?)" ;
}
} else {
fatal_error "$file does not exist!" ;
}
}
#
# Process the records in the capabilities file
#
sub read_capabilities () {
while ( read_a_line1 ) {
if ( $ currentline =~ /^([a-zA-Z]\w*)=(.*)$/ ) {
my ( $ var , $ val ) = ( $ 1 , $ 2 ) ;
unless ( exists $ capabilities { $ var } ) {
warning_message "Unknown capability ($var) ignored" ;
next ;
}
$ capabilities { $ var } = $ val =~ /^\"([^\"]*)\"$/ ? $ 1 : $ val ;
} else {
fatal_error "Unrecognized capabilities entry" ;
}
}
if ( $ capabilities { CAPVERSION } ) {
warning_message "Your capabilities file is out of date -- it does not contain all of the capabilities defined by $Product version $globals{VERSION}" unless $ capabilities { CAPVERSION } >= $ globals { CAPVERSION } ;
} else {
warning_message "Your capabilities file may not contain all of the capabilities defined by $Product version $globals{VERSION}" ;
}
2009-12-19 21:42:39 +01:00
unless ( $ capabilities { KERNELVERSION } ) {
2009-12-19 22:47:12 +01:00
warning_message "Your capabilities file does not contain a Kernel Version -- using 2.6.30" ;
$ capabilities { KERNELVERSION } = 20630 ;
2009-12-19 21:42:39 +01:00
}
2010-01-25 19:50:49 +01:00
for ( keys % capabilities ) {
$ capabilities { $ _ } = '' unless defined $ capabilities { $ _ } ;
}
2009-02-22 18:30:14 +01:00
}
#
# Get the system's capabilities, either by probing or by reading a capabilities file
#
sub get_capabilities ( $ ) {
my $ export = $ _ [ 0 ] ;
if ( ! $ export && $> == 0 ) { # $> == $EUID
my $ iptables = $ config { $ toolNAME } ;
if ( $ iptables ) {
fatal_error "$toolNAME=$iptables does not exist or is not executable" unless - x $ iptables ;
} else {
fatal_error "Can't find $toolname executable" unless $ iptables = which $ toolname ;
}
my $ iptables_restore = $ iptables . '-restore' ;
fatal_error "$iptables_restore does not exist or is not executable" unless - x $ iptables_restore ;
load_kernel_modules ;
if ( open_file 'capabilities' ) {
read_capabilities ;
} else {
determine_capabilities $ iptables ;
}
} else {
unless ( open_file 'capabilities' ) {
fatal_error "The -e compiler option requires a capabilities file" if $ export ;
fatal_error "Compiling under non-root uid requires a capabilities file" ;
}
read_capabilities ;
}
}
#
# Deal with options that we no longer support
#
sub unsupported_yes_no ( $ ) {
my $ option = shift ;
default_yes_no $ option , '' ;
2009-06-13 16:07:55 +02:00
fatal_error "$option=Yes is not supported by Shorewall $globals{VERSION}" if $ config { $ option } ;
2009-02-22 18:30:14 +01:00
}
2009-09-06 18:51:32 +02:00
sub unsupported_yes_no_warning ( $ ) {
my $ option = shift ;
default_yes_no $ option , '' ;
warning_message "$option=Yes is not supported by Shorewall $globals{VERSION}" if $ config { $ option } ;
}
2009-02-22 18:30:14 +01:00
#
# - Read the shorewall.conf file
# - Read the capabilities file, if any
# - establish global hashes %config , %globals and %capabilities
#
sub get_configuration ( $ ) {
my $ export = $ _ [ 0 ] ;
$ globals { EXPORT } = $ export ;
our ( $ once , @ originalinc ) ;
@ originalinc = @ INC unless $ once + + ;
ensure_config_path ;
process_shorewall_conf ;
ensure_config_path ;
@ INC = @ originalinc ;
unshift @ INC , @ config_path ;
default 'PATH' , '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin' ;
2010-01-29 01:39:45 +01:00
#
# get_capabilities requires that the true settings of these options be established
#
2009-02-22 18:30:14 +01:00
default 'MODULE_PREFIX' , 'o gz ko o.gz ko.gz' ;
2010-01-28 17:05:24 +01:00
default_yes_no 'LOAD_HELPERS_ONLY' , '' ;
2009-02-22 18:30:14 +01:00
get_capabilities ( $ export ) ;
if ( $ config { LOGRATE } || $ config { LOGBURST } ) {
if ( defined $ config { LOGRATE } ) {
fatal_error "Invalid LOGRATE ($config{LOGRATE})" unless $ config { LOGRATE } =~ /^\d+\/(second|minute)$/ ;
}
if ( defined $ config { LOGBURST } ) {
fatal_error "Invalid LOGBURST ($config{LOGBURST})" unless $ config { LOGBURST } =~ /^\d+$/ ;
}
$ globals { LOGLIMIT } = '-m limit ' ;
$ globals { LOGLIMIT } . = "--limit $config{LOGRATE} " if defined $ config { LOGRATE } ;
$ globals { LOGLIMIT } . = "--limit-burst $config{LOGBURST} " if defined $ config { LOGBURST } ;
} else {
$ globals { LOGLIMIT } = '' ;
}
check_trivalue ( 'IP_FORWARDING' , 'on' ) ;
2009-12-19 22:47:12 +01:00
my $ val ;
2010-01-25 19:50:49 +01:00
if ( have_capability ( 'KERNELVERSION' ) < 20631 ) {
2009-12-19 22:47:12 +01:00
check_trivalue ( 'ROUTE_FILTER' , '' ) ;
} else {
2009-12-24 00:13:43 +01:00
$ val = $ config { ROUTE_FILTER } ;
2009-12-19 22:47:12 +01:00
if ( defined $ val ) {
if ( $ val =~ /\d+/ ) {
fatal_error "Invalid value ($val) for ROUTE_FILTER" unless $ val < 3 ;
} else {
check_trivalue ( 'ROUTE_FILTER' , '' ) ;
}
2009-12-21 00:54:41 +01:00
} else {
check_trivalue ( 'ROUTE_FILTER' , '' ) ;
2009-12-19 22:47:12 +01:00
}
}
if ( $ family == F_IPV6 ) {
2009-12-24 00:13:43 +01:00
$ val = $ config { ROUTE_FILTER } ;
2010-01-11 23:16:03 +01:00
fatal_error "ROUTE_FILTER=$val is not supported in IPv6" if $ val && $ val ne 'off' ;
2009-12-19 22:47:12 +01:00
}
2009-02-22 18:30:14 +01:00
if ( $ family == F_IPV4 ) {
check_trivalue ( 'LOG_MARTIANS' , 'on' ) ;
} else {
check_trivalue ( 'LOG_MARTIANS' , 'off' ) ;
fatal_error "LOG_MARTIANS=On is not supported in IPv6" if $ config { LOG_MARTIANS } eq 'on' ;
}
default 'STARTUP_LOG' , '' ;
if ( $ config { STARTUP_LOG } ne '' ) {
if ( defined $ config { LOG_VERBOSITY } ) {
if ( $ config { LOG_VERBOSITY } eq '' ) {
$ config { LOG_VERBOSITY } = 2 ;
} else {
my $ val = numeric_value ( $ config { LOG_VERBOSITY } ) ;
fatal_error "Invalid LOG_VERBOSITY ($config{LOG_VERBOSITY} )" unless defined ( $ val ) && ( $ val >= - 1 ) && ( $ val <= 2 ) ;
$ config { STARTUP_LOG } = '' if $ config { LOG_VERBOSITY } < 0 ;
}
} else {
$ config { LOG_VERBOSITY } = 2 ;
}
} else {
$ config { LOG_VERBOSITY } = - 1 ;
}
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' , $ family == F_IPV4 ? 'Yes' : '' ;
if ( defined $ config { CLAMPMSS } ) {
default_yes_no 'CLAMPMSS' , '' unless $ config { CLAMPMSS } =~ /^\d+$/ ;
} else {
$ config { CLAMPMSS } = '' ;
}
unless ( $ config { ADD_IP_ALIASES } || $ config { ADD_SNAT_ALIASES } ) {
$ config { RETAIN_ALIASES } = '' ;
} else {
default_yes_no_ipv4 'RETAIN_ALIASES' , '' ;
}
default_yes_no 'ADMINISABSENTMINDED' , '' ;
default_yes_no 'BLACKLISTNEWONLY' , '' ;
2009-07-07 03:23:23 +02:00
default_yes_no 'DISABLE_IPV6' , '' ;
2009-02-22 18:30:14 +01:00
2009-09-06 18:51:32 +02:00
unsupported_yes_no_warning 'DYNAMIC_ZONES' ;
unsupported_yes_no 'BRIDGING' ;
unsupported_yes_no_warning 'RFC1918_STRICT' ;
2009-02-22 18:30:14 +01:00
2010-01-04 20:14:05 +01:00
default_yes_no 'SAVE_IPSETS' , '' ;
2009-02-22 18:30:14 +01:00
default_yes_no 'STARTUP_ENABLED' , 'Yes' ;
default_yes_no 'DELAYBLACKLISTLOAD' , '' ;
2009-09-06 22:37:24 +02:00
default_yes_no 'MAPOLDACTIONS' , 'Yes' ;
2009-02-22 18:30:14 +01:00
2009-06-13 16:07:55 +02:00
warning_message 'DELAYBLACKLISTLOAD=Yes is not supported by Shorewall ' . $ globals { VERSION } if $ config { DELAYBLACKLISTLOAD } ;
2009-02-22 18:30:14 +01:00
default_yes_no 'LOGTAGONLY' , '' ; $ globals { LOGTAGONLY } = $ config { LOGTAGONLY } ;
2009-06-05 19:51:30 +02:00
2009-02-22 18:30:14 +01:00
default_yes_no 'FASTACCEPT' , '' ;
fatal_error "BLACKLISTNEWONLY=No may not be specified with FASTACCEPT=Yes" if $ config { FASTACCEPT } && ! $ config { BLACKLISTNEWONLY } ;
default_yes_no 'IMPLICIT_CONTINUE' , '' ;
default_yes_no 'HIGH_ROUTE_MARKS' , '' ;
default_yes_no 'TC_EXPERT' , '' ;
default_yes_no 'USE_ACTIONS' , 'Yes' ;
2009-06-13 16:07:55 +02:00
warning_message 'USE_ACTIONS=No is not supported by Shorewall ' . $ globals { VERSION } unless $ config { USE_ACTIONS } ;
2009-02-22 18:30:14 +01:00
default_yes_no 'EXPORTPARAMS' , '' ;
default_yes_no 'EXPAND_POLICIES' , '' ;
default_yes_no 'KEEP_RT_TABLES' , '' ;
default_yes_no 'DELETE_THEN_ADD' , 'Yes' ;
default_yes_no 'AUTO_COMMENT' , 'Yes' ;
default_yes_no 'MULTICAST' , '' ;
default_yes_no 'MARK_IN_FORWARD_CHAIN' , '' ;
default_yes_no 'MANGLE_ENABLED' , 'Yes' ;
default_yes_no 'NULL_ROUTE_RFC1918' , '' ;
default_yes_no 'USE_DEFAULT_RT' , '' ;
default_yes_no 'RESTORE_DEFAULT_ROUTE' , 'Yes' ;
2009-03-31 19:31:23 +02:00
default_yes_no 'AUTOMAKE' , '' ;
2009-04-20 22:26:47 +02:00
default_yes_no 'WIDE_TC_MARKS' , '' ;
2009-10-20 22:24:17 +02:00
default_yes_no 'TRACK_PROVIDERS' , '' ;
2010-01-16 18:53:53 +01:00
default_yes_no 'ACCOUNTING' , 'Yes' ;
default_yes_no 'OPTIMIZE_ACCOUNTING' , '' ;
default_yes_no 'DYNAMIC_BLACKLIST' , 'Yes' ;
2009-02-22 18:30:14 +01:00
2010-01-11 23:16:03 +01:00
numeric_option 'TC_BITS' , $ config { WIDE_TC_MARKS } ? 14 : 8 , 0 ;
numeric_option 'MASK_BITS' , $ config { WIDE_TC_MARKS } ? 16 : 8 , $ config { TC_BITS } ;
numeric_option 'PROVIDER_BITS' , 8 , 0 ;
numeric_option 'PROVIDER_OFFSET' , $ config { HIGH_ROUTE_MARKS } ? $ config { WIDE_TC_MARKS } ? 16 : 8 : 0 , 0 ;
if ( $ config { PROVIDER_OFFSET } ) {
$ config { PROVIDER_OFFSET } = $ config { MASK_BITS } if $ config { PROVIDER_OFFSET } < $ config { MASK_BITS } ;
fatal_error 'PROVIDER_BITS + PROVIDER_OFFSET > 32' if $ config { PROVIDER_BITS } + $ config { PROVIDER_OFFSET } > 32 ;
}
$ globals { TC_MAX } = make_mask ( $ config { TC_BITS } ) ;
$ globals { TC_MASK } = make_mask ( $ config { MASK_BITS } ) ;
$ globals { PROVIDER_MIN } = 1 << $ config { PROVIDER_OFFSET } ;
$ globals { PROVIDER_MASK } = make_mask ( $ config { PROVIDER_BITS } ) << $ config { PROVIDER_OFFSET } ;
2009-11-10 23:12:55 +01:00
if ( defined ( $ val = $ config { ZONE2ZONE } ) ) {
fatal_error "Invalid ZONE2ZONE value ( $val )" unless $ val =~ /^[2-]$/ ;
} else {
$ config { ZONE2ZONE } = '2' ;
}
default 'BLACKLIST_DISPOSITION' , 'DROP' ;
2009-02-22 18:30:14 +01:00
default_log_level 'BLACKLIST_LOGLEVEL' , '' ;
default_log_level 'MACLIST_LOG_LEVEL' , '' ;
default_log_level 'TCP_FLAGS_LOG_LEVEL' , '' ;
2009-06-05 19:51:30 +02:00
default_log_level 'RFC1918_LOG_LEVEL' , '' ;
warning_message "RFC1918_LOG_LEVEL=$config{RFC1918_LOG_LEVEL} ignored. The 'norfc1918' interface/host option is no longer supported" if $ config { RFC1918_LOG_LEVEL } ;
2009-02-22 18:30:14 +01:00
default_log_level 'SMURF_LOG_LEVEL' , '' ;
default_log_level 'LOGALLNEW' , '' ;
$ globals { MACLIST_TARGET } = 'reject' ;
if ( $ val = $ config { MACLIST_DISPOSITION } ) {
unless ( $ val eq 'REJECT' ) {
if ( $ val eq 'DROP' ) {
$ globals { MACLIST_TARGET } = 'DROP' ;
} elsif ( $ val eq 'ACCEPT' ) {
$ globals { MACLIST_TARGET } = 'RETURN' ;
} else {
fatal_error "Invalid value ($config{MACLIST_DISPOSITION}) for MACLIST_DISPOSITION"
}
}
} else {
$ config { MACLIST_DISPOSITION } = 'REJECT' ;
}
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' ;
}
} else {
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' ;
}
default 'TC_ENABLED' , $ family == F_IPV4 ? 'Internal' : 'no' ;
$ val = "\L$config{TC_ENABLED}" ;
if ( $ val eq 'yes' ) {
my $ file = find_file 'tcstart' ;
fatal_error "Unable to find tcstart file" unless - f $ file ;
$ globals { TC_SCRIPT } = $ file ;
} elsif ( $ val eq 'internal' ) {
$ config { TC_ENABLED } = 'Internal' ;
2010-01-13 02:01:20 +01:00
} elsif ( $ val eq 'simple' ) {
$ config { TC_ENABLED } = 'Simple' ;
2009-02-22 18:30:14 +01:00
} else {
fatal_error "Invalid value ($config{TC_ENABLED}) for TC_ENABLED" unless $ val eq 'no' ;
$ config { TC_ENABLED } = '' ;
}
2010-01-11 23:16:03 +01:00
if ( $ config { TC_ENABLED } ) {
fatal_error "TC_ENABLED=$config{TC_ENABLED} is not allowed with MANGLE_ENABLED=No" unless $ config { MANGLE_ENABLED } ;
require_capability 'MANGLE_ENABLED' , "TC_ENABLED=$config{TC_ENABLED}" , 's' ;
}
2009-02-22 18:30:14 +01:00
2010-01-13 02:01:20 +01:00
if ( $ val = $ config { TC_PRIOMAP } ) {
my @ priomap = split ' ' , $ val ;
fatal_error "Invalid TC_PRIOMAP ($val)" unless @ priomap == 16 ;
for ( @ priomap ) {
fatal_error "Invalid TC_PRIOMAP entry ($_)" unless /[1-3]/ ;
$ _ - - ;
}
$ config { TC_PRIOMAP } = join ' ' , @ priomap ;
} else {
$ config { TC_PRIOMAP } = '1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1' ;
}
2009-02-22 18:30:14 +01:00
default 'RESTOREFILE' , 'restore' ;
default 'IPSECFILE' , 'zones' ;
default 'DROP_DEFAULT' , 'Drop' ;
default 'REJECT_DEFAULT' , 'Reject' ;
default 'QUEUE_DEFAULT' , 'none' ;
default 'NFQUEUE_DEFAULT' , 'none' ;
default 'ACCEPT_DEFAULT' , 'none' ;
default 'OPTIMIZE' , 0 ;
2009-08-26 19:34:04 +02:00
fatal_error 'IPSECFILE=ipsec is not supported by Shorewall ' . $ globals { VERSION } if $ config { IPSECFILE } eq 'ipsec' ;
fatal_error "Invalid IPSECFILE value ($config{IPSECFILE}" unless $ config { IPSECFILE } eq 'zones' ;
2009-02-22 18:30:14 +01:00
for my $ default qw/DROP_DEFAULT REJECT_DEFAULT QUEUE_DEFAULT NFQUEUE_DEFAULT ACCEPT_DEFAULT/ {
$ config { $ default } = 'none' if "\L$config{$default}" eq 'none' ;
}
2010-01-11 23:16:03 +01:00
$ val = numeric_value $ config { OPTIMIZE } ;
2009-02-22 18:30:14 +01:00
2010-01-16 18:53:53 +01:00
fatal_error "Invalid OPTIMIZE value ($config{OPTIMIZE})" unless defined ( $ val ) && $ val >= 0 && $ val <= 7 ;
2009-02-22 18:30:14 +01:00
$ globals { MARKING_CHAIN } = $ config { MARK_IN_FORWARD_CHAIN } ? 'tcfor' : 'tcpre' ;
if ( $ val = $ config { LOGFORMAT } ) {
my $ result ;
eval {
if ( $ val =~ /%d/ ) {
$ globals { LOGRULENUMBERS } = 'Yes' ;
$ result = sprintf "$val" , 'fooxx2barxx' , 1 , 'ACCEPT' ;
} else {
$ result = sprintf "$val" , 'fooxx2barxx' , 'ACCEPT' ;
}
} ;
fatal_error "Invalid LOGFORMAT ($val)" if $@ ;
fatal_error "LOGFORMAT string is longer than 29 characters ($val)" if length $ result > 29 ;
$ globals { MAXZONENAMELENGTH } = int ( 5 + ( ( 29 - ( length $ result ) ) / 2 ) ) ;
} else {
$ config { LOGFORMAT } = 'Shorewall:%s:%s:' ;
$ globals { MAXZONENAMELENGTH } = 5 ;
}
if ( $ config { LOCKFILE } ) {
my ( $ file , $ dir , $ suffix ) ;
eval {
( $ file , $ dir , $ suffix ) = fileparse ( $ config { LOCKFILE } ) ;
} ;
2009-08-26 19:34:04 +02:00
cleanup , die $@ if $@ ;
2009-02-22 18:30:14 +01:00
fatal_error "LOCKFILE=$config{LOCKFILE}: Directory $dir does not exist" unless $ export or - d $ dir ;
} else {
$ config { LOCKFILE } = '' ;
}
}
#
2009-10-06 00:43:29 +02:00
# The values of the options in @propagateconfig are copied to the script file in OPTION=<value> format.
2009-02-22 18:30:14 +01:00
#
sub propagateconfig () {
for my $ option ( @ propagateconfig ) {
my $ value = $ config { $ option } || '' ;
emit "$option=\"$value\"" ;
}
}
#
# Add a shell script file to the output script -- Return true if the
2009-06-29 17:14:53 +02:00
# file exists and is not in /usr/share/shorewall/ and is non-empty.
2009-02-22 18:30:14 +01:00
#
2009-06-29 17:14:53 +02:00
sub append_file ( $;$ ) {
2009-02-22 18:30:14 +01:00
my $ user_exit = find_file $ _ [ 0 ] ;
my $ result = 0 ;
unless ( $ user_exit =~ /^($globals{SHAREDIR})/ ) {
if ( - f $ user_exit ) {
2009-06-29 17:14:53 +02:00
if ( $ _ [ 1 ] ) {
#
# Suppress progress message
#
$ result = copy1 $ user_exit ;
} else {
#
# Include progress message -- Pretend progress_message call was in the file
2009-08-20 23:32:15 +02:00
#
2009-06-29 17:14:53 +02:00
$ result = 1 ;
save_progress_message "Processing $user_exit ..." ;
copy1 $ user_exit ;
}
2009-02-22 18:30:14 +01:00
}
}
$ result ;
}
#
# 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..." ;
my $ command = qq( package Shorewall::User;\nno strict;\n# line 1 "$file"\n ) . `cat $file` ;
unless ( my $ return = eval $ command ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
unless ( defined $ return ) {
2009-08-20 23:32:15 +02:00
fatal_error "Couldn't do $file: $!" if $! ;
2009-02-22 18:30:14 +01:00
fatal_error "Couldn't do $file" ;
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
fatal_error "$file returned a false value" ;
}
}
}
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_line1 ) {
close_file ;
my $ command = qq( package Shorewall::User;\n# line 1 "$file"\n ) . `cat $file` ;
unless ( my $ return = eval $ command ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
unless ( defined $ return ) {
fatal_error "Couldn't do $file: $!" if $! ;
fatal_error "Couldn't do $file" ;
}
fatal_error "$file returned a false value" ;
}
} else {
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_line1 ) {
close_file ;
unless ( my $ return = eval `cat $file` ) {
fatal_error "Couldn't parse $file: $@" if $@ ;
unless ( defined $ return ) {
fatal_error "Couldn't do $file: $!" if $! ;
fatal_error "Couldn't do $file" ;
}
fatal_error "$file returned a false value" ;
}
}
pop_open ;
}
}
#
# Generate the aux config file for Shorewall Lite
#
sub generate_aux_config () {
sub conditionally_add_option ( $ ) {
my $ option = $ _ [ 0 ] ;
my $ value = $ config { $ option } ;
emit "[ -n \"\${$option:=$value}\" ]" if defined $ value && $ value ne '' ;
}
sub conditionally_add_option1 ( $ ) {
my $ option = $ _ [ 0 ] ;
my $ value = $ config { $ option } ;
emit "$option=\"$value\"" if $ value ;
}
create_temp_aux_config ;
my $ date = localtime ;
2009-06-13 16:07:55 +02:00
emit "#\n# Shorewall auxiliary configuration file created by Shorewall version $globals{VERSION} - $date\n#" ;
2009-02-22 18:30:14 +01:00
2009-05-28 16:22:48 +02:00
for my $ option qw( VERBOSITY LOGFILE LOGFORMAT IPTABLES IP6TABLES IP TC IPSET PATH SHOREWALL_SHELL SUBSYSLOCK LOCKFILE RESTOREFILE ) {
2009-02-22 18:30:14 +01:00
conditionally_add_option $ option ;
}
conditionally_add_option1 'TC_ENABLED' ;
finalize_aux_config ;
}
END {
2009-08-26 19:34:04 +02:00
cleanup ;
2009-02-22 18:30:14 +01:00
}
1 ;