mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-16 12:43:19 +01:00
bfe9682521
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@6619 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
1838 lines
46 KiB
Perl
1838 lines
46 KiB
Perl
#
|
|
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Config.pm
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
#
|
|
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# Complete documentation is available at http://shorewall.net
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of Version 2 of the GNU General Public License
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
#
|
|
# 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.
|
|
#
|
|
package Shorewall::Config;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Shorewall::Common;
|
|
use File::Basename;
|
|
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT = qw(
|
|
warning_message
|
|
fatal_error
|
|
set_shorewall_dir
|
|
find_file
|
|
split_line
|
|
split_line1
|
|
split_line2
|
|
open_file
|
|
close_file
|
|
push_open
|
|
pop_open
|
|
read_a_line
|
|
read_a_line1
|
|
validate_level
|
|
qt
|
|
ensure_config_path
|
|
get_configuration
|
|
require_capability
|
|
report_capabilities
|
|
propagateconfig
|
|
append_file
|
|
run_user_exit
|
|
run_user_exit1
|
|
run_user_exit2
|
|
generate_aux_config
|
|
|
|
%config
|
|
%globals
|
|
%capabilities
|
|
%protocols
|
|
%services );
|
|
|
|
our @EXPORT_OK = qw( $shorewall_dir initialize );
|
|
our @VERSION = 1.00;
|
|
|
|
#
|
|
# Misc Globals
|
|
#
|
|
our %globals;
|
|
#
|
|
# From shorewall.conf file
|
|
#
|
|
our %config;
|
|
#
|
|
# Config options and global settings that are to be copied to object script
|
|
#
|
|
our @propagateconfig = qw/ DISABLE_IPV6 MODULESDIR MODULE_SUFFIX LOGFORMAT SUBSYSLOCK LOCKFILE /;
|
|
our @propagateenv = qw/ LOGLIMIT LOGTAGONLY LOGRULENUMBERS /;
|
|
#
|
|
# From parsing the capabilities file
|
|
#
|
|
our %capabilities;
|
|
#
|
|
# /etc/protocols and /etc/services
|
|
#
|
|
# Protocol and Services tables generated using buildproto.pl - Wed Jun 20 12:47:57 2007
|
|
#
|
|
our %protocols = (
|
|
ip => 0,
|
|
IP => 0,
|
|
icmp => 1,
|
|
ICMP => 1,
|
|
igmp => 2,
|
|
IGMP => 2,
|
|
ggp => 3,
|
|
GGP => 3,
|
|
ipencap => 4,
|
|
'IP-ENCAP' => 4,
|
|
st => 5,
|
|
ST => 5,
|
|
tcp => 6,
|
|
TCP => 6,
|
|
egp => 8,
|
|
EGP => 8,
|
|
igp => 9,
|
|
IGP => 9,
|
|
pup => 12,
|
|
PUP => 12,
|
|
udp => 17,
|
|
UDP => 17,
|
|
hmp => 20,
|
|
HMP => 20,
|
|
'xns-idp' => 22,
|
|
'XNS-IDP' => 22,
|
|
rdp => 27,
|
|
RDP => 27,
|
|
'iso-tp4' => 29,
|
|
'ISO-TP4' => 29,
|
|
xtp => 36,
|
|
XTP => 36,
|
|
ddp => 37,
|
|
DDP => 37,
|
|
'idpr-cmtp' => 38,
|
|
'IDPR-CMTP' => 38,
|
|
ipv6 => 41,
|
|
IPv6 => 41,
|
|
'ipv6-route' => 43,
|
|
'IPv6-Route' => 43,
|
|
'ipv6-frag' => 44,
|
|
'IPv6-Frag' => 44,
|
|
idrp => 45,
|
|
IDRP => 45,
|
|
rsvp => 46,
|
|
RSVP => 46,
|
|
gre => 47,
|
|
GRE => 47,
|
|
esp => 50,
|
|
'IPSEC-ESP' => 50,
|
|
ah => 51,
|
|
'IPSEC-AH' => 51,
|
|
skip => 57,
|
|
SKIP => 57,
|
|
'ipv6-icmp' => 58,
|
|
'IPv6-ICMP' => 58,
|
|
'ipv6-nonxt' => 59,
|
|
'IPv6-NoNxt' => 59,
|
|
'ipv6-opts' => 60,
|
|
'IPv6-Opts' => 60,
|
|
rspf => 73,
|
|
vmtp => 81,
|
|
VMTP => 81,
|
|
eigrp => 88,
|
|
EIGRP => 88,
|
|
ospf => 89,
|
|
OSPFIGP => 89,
|
|
'ax.25' => 93,
|
|
'AX.25' => 93,
|
|
ipip => 94,
|
|
IPIP => 94,
|
|
etherip => 97,
|
|
ETHERIP => 97,
|
|
encap => 98,
|
|
ENCAP => 98,
|
|
pim => 103,
|
|
PIM => 103,
|
|
ipcomp => 108,
|
|
IPCOMP => 108,
|
|
vrrp => 112,
|
|
VRRP => 112,
|
|
l2tp => 115,
|
|
L2TP => 115,
|
|
isis => 124,
|
|
ISIS => 124,
|
|
sctp => 132,
|
|
SCTP => 132,
|
|
fc => 133,
|
|
FC => 133,
|
|
);
|
|
|
|
our %services = (
|
|
tcpmux => 1,
|
|
echo => 7,
|
|
discard => 9,
|
|
sink => 9,
|
|
null => 9,
|
|
systat => 11,
|
|
users => 11,
|
|
daytime => 13,
|
|
netstat => 15,
|
|
qotd => 17,
|
|
quote => 17,
|
|
msp => 18,
|
|
chargen => 19,
|
|
ttytst => 19,
|
|
source => 19,
|
|
'ftp-data' => 20,
|
|
ftp => 21,
|
|
fsp => 21,
|
|
fspd => 21,
|
|
ssh => 22,
|
|
telnet => 23,
|
|
smtp => 25,
|
|
mail => 25,
|
|
time => 37,
|
|
timserver => 37,
|
|
rlp => 39,
|
|
resource => 39,
|
|
nameserver => 42,
|
|
name => 42,
|
|
whois => 43,
|
|
nicname => 43,
|
|
tacacs => 49,
|
|
're-mail-ck' => 50,
|
|
domain => 53,
|
|
mtp => 57,
|
|
'tacacs-ds' => 65,
|
|
bootps => 67,
|
|
bootpc => 68,
|
|
tftp => 69,
|
|
gopher => 70,
|
|
rje => 77,
|
|
netrjs => 77,
|
|
finger => 79,
|
|
www => 80,
|
|
http => 80,
|
|
link => 87,
|
|
ttylink => 87,
|
|
kerberos => 88,
|
|
kerberos5 => 88,
|
|
krb5 => 88,
|
|
'kerberos-sec' => 88,
|
|
supdup => 95,
|
|
hostnames => 101,
|
|
hostname => 101,
|
|
'iso-tsap' => 102,
|
|
tsap => 102,
|
|
'acr-nema' => 104,
|
|
dicom => 104,
|
|
'csnet-ns' => 105,
|
|
'cso-ns' => 105,
|
|
rtelnet => 107,
|
|
pop2 => 109,
|
|
postoffice => 109,
|
|
'pop-2' => 109,
|
|
pop3 => 110,
|
|
'pop-3' => 110,
|
|
sunrpc => 111,
|
|
portmapper => 111,
|
|
auth => 113,
|
|
authentication => 113,
|
|
tap => 113,
|
|
ident => 113,
|
|
sftp => 115,
|
|
'uucp-path' => 117,
|
|
nntp => 119,
|
|
readnews => 119,
|
|
untp => 119,
|
|
ntp => 123,
|
|
pwdgen => 129,
|
|
'loc-srv' => 135,
|
|
epmap => 135,
|
|
'netbios-ns' => 137,
|
|
'netbios-dgm' => 138,
|
|
'netbios-ssn' => 139,
|
|
imap2 => 143,
|
|
imap => 143,
|
|
snmp => 161,
|
|
'snmp-trap' => 162,
|
|
snmptrap => 162,
|
|
'cmip-man' => 163,
|
|
'cmip-agent' => 164,
|
|
mailq => 174,
|
|
xdmcp => 177,
|
|
nextstep => 178,
|
|
NeXTStep => 178,
|
|
NextStep => 178,
|
|
bgp => 179,
|
|
prospero => 191,
|
|
irc => 194,
|
|
smux => 199,
|
|
'at-rtmp' => 201,
|
|
'at-nbp' => 202,
|
|
'at-echo' => 204,
|
|
'at-zis' => 206,
|
|
qmtp => 209,
|
|
z3950 => 210,
|
|
wais => 210,
|
|
ipx => 213,
|
|
imap3 => 220,
|
|
pawserv => 345,
|
|
zserv => 346,
|
|
fatserv => 347,
|
|
rpc2portmap => 369,
|
|
codaauth2 => 370,
|
|
clearcase => 371,
|
|
Clearcase => 371,
|
|
ulistserv => 372,
|
|
ldap => 389,
|
|
imsp => 406,
|
|
https => 443,
|
|
snpp => 444,
|
|
'microsoft-ds' => 445,
|
|
kpasswd => 464,
|
|
saft => 487,
|
|
isakmp => 500,
|
|
rtsp => 554,
|
|
nqs => 607,
|
|
'npmp-local' => 610,
|
|
dqs313_qmaster => 610,
|
|
'npmp-gui' => 611,
|
|
dqs313_execd => 611,
|
|
'hmmp-ind' => 612,
|
|
dqs313_intercell => 612,
|
|
ipp => 631,
|
|
exec => 512,
|
|
biff => 512,
|
|
comsat => 512,
|
|
login => 513,
|
|
who => 513,
|
|
whod => 513,
|
|
shell => 514,
|
|
cmd => 514,
|
|
syslog => 514,
|
|
printer => 515,
|
|
spooler => 515,
|
|
talk => 517,
|
|
ntalk => 518,
|
|
route => 520,
|
|
router => 520,
|
|
routed => 520,
|
|
timed => 525,
|
|
timeserver => 525,
|
|
tempo => 526,
|
|
newdate => 526,
|
|
courier => 530,
|
|
rpc => 530,
|
|
conference => 531,
|
|
chat => 531,
|
|
netnews => 532,
|
|
netwall => 533,
|
|
gdomap => 538,
|
|
uucp => 540,
|
|
uucpd => 540,
|
|
klogin => 543,
|
|
kshell => 544,
|
|
krcmd => 544,
|
|
afpovertcp => 548,
|
|
remotefs => 556,
|
|
rfs_server => 556,
|
|
rfs => 556,
|
|
nntps => 563,
|
|
snntp => 563,
|
|
submission => 587,
|
|
ldaps => 636,
|
|
tinc => 655,
|
|
silc => 706,
|
|
'kerberos-adm' => 749,
|
|
webster => 765,
|
|
rsync => 873,
|
|
'ftps-data' => 989,
|
|
ftps => 990,
|
|
telnets => 992,
|
|
imaps => 993,
|
|
ircs => 994,
|
|
pop3s => 995,
|
|
socks => 1080,
|
|
proofd => 1093,
|
|
rootd => 1094,
|
|
openvpn => 1194,
|
|
rmiregistry => 1099,
|
|
kazaa => 1214,
|
|
nessus => 1241,
|
|
lotusnote => 1352,
|
|
lotusnotes => 1352,
|
|
'ms-sql-s' => 1433,
|
|
'ms-sql-m' => 1434,
|
|
ingreslock => 1524,
|
|
'prospero-np' => 1525,
|
|
datametrics => 1645,
|
|
'old-radius' => 1645,
|
|
'sa-msg-port' => 1646,
|
|
'old-radacct' => 1646,
|
|
kermit => 1649,
|
|
l2f => 1701,
|
|
l2tp => 1701,
|
|
radius => 1812,
|
|
'radius-acct' => 1813,
|
|
radacct => 1813,
|
|
msnp => 1863,
|
|
'unix-status' => 1957,
|
|
'log-server' => 1958,
|
|
remoteping => 1959,
|
|
nfs => 2049,
|
|
'rtcm-sc104' => 2101,
|
|
cvspserver => 2401,
|
|
venus => 2430,
|
|
'venus-se' => 2431,
|
|
codasrv => 2432,
|
|
'codasrv-se' => 2433,
|
|
mon => 2583,
|
|
dict => 2628,
|
|
gpsd => 2947,
|
|
gds_db => 3050,
|
|
icpv2 => 3130,
|
|
icp => 3130,
|
|
mysql => 3306,
|
|
nut => 3493,
|
|
distcc => 3632,
|
|
daap => 3689,
|
|
svn => 3690,
|
|
subversion => 3690,
|
|
iax => 4569,
|
|
'radmin-port' => 4899,
|
|
rfe => 5002,
|
|
mmcc => 5050,
|
|
sip => 5060,
|
|
'sip-tls' => 5061,
|
|
aol => 5190,
|
|
'xmpp-client' => 5222,
|
|
'jabber-client' => 5222,
|
|
'xmpp-server' => 5269,
|
|
'jabber-server' => 5269,
|
|
cfengine => 5308,
|
|
postgresql => 5432,
|
|
postgres => 5432,
|
|
x11 => 6000,
|
|
'x11-0' => 6000,
|
|
'x11-1' => 6001,
|
|
'x11-2' => 6002,
|
|
'x11-3' => 6003,
|
|
'x11-4' => 6004,
|
|
'x11-5' => 6005,
|
|
'x11-6' => 6006,
|
|
'x11-7' => 6007,
|
|
'gnutella-svc' => 6346,
|
|
'gnutella-rtr' => 6347,
|
|
'afs3-fileserver' => 7000,
|
|
bbs => 7000,
|
|
'afs3-callback' => 7001,
|
|
'afs3-prserver' => 7002,
|
|
'afs3-vlserver' => 7003,
|
|
'afs3-kaserver' => 7004,
|
|
'afs3-volser' => 7005,
|
|
'afs3-errors' => 7006,
|
|
'afs3-bos' => 7007,
|
|
'afs3-update' => 7008,
|
|
'afs3-rmtsys' => 7009,
|
|
'font-service' => 7100,
|
|
xfs => 7100,
|
|
'bacula-dir' => 9101,
|
|
'bacula-fd' => 9102,
|
|
'bacula-sd' => 9103,
|
|
amanda => 10080,
|
|
hkp => 11371,
|
|
bprd => 13720,
|
|
bpdbm => 13721,
|
|
'bpjava-msvc' => 13722,
|
|
vnetd => 13724,
|
|
bpcd => 13782,
|
|
vopied => 13783,
|
|
wnn6 => 22273,
|
|
rtmp => 1,
|
|
nbp => 2,
|
|
zip => 6,
|
|
kerberos4 => 750,
|
|
'kerberos-iv' => 750,
|
|
kdc => 750,
|
|
kerberos_master => 751,
|
|
passwd_server => 752,
|
|
krb_prop => 754,
|
|
krb5_prop => 754,
|
|
hprop => 754,
|
|
krbupdate => 760,
|
|
kreg => 760,
|
|
swat => 901,
|
|
kpop => 1109,
|
|
knetd => 2053,
|
|
'zephyr-srv' => 2102,
|
|
'zephyr-clt' => 2103,
|
|
'zephyr-hm' => 2104,
|
|
eklogin => 2105,
|
|
kx => 2111,
|
|
iprop => 2121,
|
|
supfilesrv => 871,
|
|
supfiledbg => 1127,
|
|
linuxconf => 98,
|
|
poppassd => 106,
|
|
ssmtp => 465,
|
|
smtps => 465,
|
|
moira_db => 775,
|
|
moira_update => 777,
|
|
moira_ureg => 779,
|
|
spamd => 783,
|
|
omirr => 808,
|
|
omirrd => 808,
|
|
customs => 1001,
|
|
skkserv => 1178,
|
|
predict => 1210,
|
|
rmtcfg => 1236,
|
|
wipld => 1300,
|
|
xtel => 1313,
|
|
xtelw => 1314,
|
|
support => 1529,
|
|
sieve => 2000,
|
|
cfinger => 2003,
|
|
ndtp => 2010,
|
|
frox => 2121,
|
|
ninstall => 2150,
|
|
zebrasrv => 2600,
|
|
zebra => 2601,
|
|
ripd => 2602,
|
|
ripngd => 2603,
|
|
ospfd => 2604,
|
|
bgpd => 2605,
|
|
ospf6d => 2606,
|
|
ospfapi => 2607,
|
|
isisd => 2608,
|
|
afbackup => 2988,
|
|
afmbackup => 2989,
|
|
xtell => 4224,
|
|
fax => 4557,
|
|
hylafax => 4559,
|
|
distmp3 => 4600,
|
|
munin => 4949,
|
|
lrrd => 4949,
|
|
'enbd-cstatd' => 5051,
|
|
'enbd-sstatd' => 5052,
|
|
pcrd => 5151,
|
|
noclog => 5354,
|
|
hostmon => 5355,
|
|
rplay => 5555,
|
|
rptp => 5556,
|
|
nsca => 5667,
|
|
mrtd => 5674,
|
|
bgpsim => 5675,
|
|
canna => 5680,
|
|
'sane-port' => 6566,
|
|
sane => 6566,
|
|
saned => 6566,
|
|
ircd => 6667,
|
|
'zope-ftp' => 8021,
|
|
webcache => 8080,
|
|
tproxy => 8081,
|
|
omniorb => 8088,
|
|
'clc-build-daemon' => 8990,
|
|
xinetd => 9098,
|
|
mandelspawn => 9359,
|
|
mandelbrot => 9359,
|
|
zope => 9673,
|
|
kamanda => 10081,
|
|
amandaidx => 10082,
|
|
amidxtape => 10083,
|
|
smsqp => 11201,
|
|
xpilot => 15345,
|
|
'sgi-cmsd' => 17001,
|
|
'sgi-crsd' => 17002,
|
|
'sgi-gcd' => 17003,
|
|
'sgi-cad' => 17004,
|
|
isdnlog => 20011,
|
|
vboxd => 20012,
|
|
binkp => 24554,
|
|
asp => 27374,
|
|
csync2 => 30865,
|
|
dircproxy => 57000,
|
|
tfido => 60177,
|
|
fido => 60179,
|
|
);
|
|
#
|
|
# Capabilities
|
|
#
|
|
our %capdesc;
|
|
#
|
|
# Directories to search for configuration files
|
|
#
|
|
our @config_path;
|
|
#
|
|
# Stash away file references here when we encounter INCLUDE
|
|
#
|
|
our @includestack;
|
|
#
|
|
# Allow nested opens
|
|
#
|
|
our @openstack;
|
|
|
|
our $currentfile; # File handle reference
|
|
our $currentfilename; # File NAME
|
|
our $currentlinenumber; # Line number
|
|
|
|
our $shorewall_dir; #Shorewall Directory
|
|
|
|
#
|
|
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
# the compiler to run multiple times in the same process. The
|
|
# initialize() function does globals initialization for this
|
|
# module and is called from an INIT block below. The function is
|
|
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
# the second and subsequent calls to that function.
|
|
#
|
|
sub initialize() {
|
|
#
|
|
# Misc Globals
|
|
#
|
|
%globals = ( SHAREDIR => '/usr/share/shorewall' ,
|
|
CONFDIR => '/etc/shorewall',
|
|
SHAREDIRPL => '/usr/share/shorewall-perl/',
|
|
ORIGINAL_POLICY_MATCH => '',
|
|
LOGPARMS => '',
|
|
TC_SCRIPT => '',
|
|
VERSION => '4.0.0-Beta5',
|
|
CAPVERSION => 30405 ,
|
|
);
|
|
#
|
|
# From shorewall.conf file
|
|
#
|
|
%config =
|
|
( STARTUP_ENABLED => undef,
|
|
VERBOSITY => undef,
|
|
#
|
|
# Logging
|
|
#
|
|
LOGFILE => undef,
|
|
LOGFORMAT => undef,
|
|
LOGTAGONLY => undef,
|
|
LOGRATE => undef,
|
|
LOGBURST => undef,
|
|
LOGALLNEW => undef,
|
|
BLACKLIST_LOGLEVEL => undef,
|
|
MACLIST_LOG_LEVEL => undef,
|
|
TCP_FLAGS_LOG_LEVEL => undef,
|
|
RFC1918_LOG_LEVEL => undef,
|
|
SMURF_LOG_LEVEL => undef,
|
|
LOG_MARTIANS => undef,
|
|
#
|
|
# Location of Files
|
|
#
|
|
IPTABLES => undef,
|
|
#
|
|
#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,
|
|
#
|
|
# 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,
|
|
CLEAR_TC => undef,
|
|
MARK_IN_FORWARD_CHAIN => undef,
|
|
CLAMPMSS => undef,
|
|
ROUTE_FILTER => undef,
|
|
DETECT_DNAT_IPADDRS => undef,
|
|
MUTEX_TIMEOUT => undef,
|
|
ADMINISABSENTMINDED => undef,
|
|
BLACKLISTNEWONLY => undef,
|
|
DELAYBLACKLISTLOAD => undef,
|
|
MODULE_SUFFIX => undef,
|
|
DISABLE_IPV6 => undef,
|
|
DYNAMIC_ZONES => undef,
|
|
PKTTYPE=> undef,
|
|
RFC1918_STRICT => undef,
|
|
MACLIST_TABLE => undef,
|
|
MACLIST_TTL => undef,
|
|
SAVE_IPSETS => undef,
|
|
MAPOLDACTIONS => undef,
|
|
FASTACCEPT => undef,
|
|
IMPLICIT_CONTINUE => undef,
|
|
HIGH_ROUTE_MARKS => undef,
|
|
USE_ACTIONS=> undef,
|
|
OPTIMIZE => undef,
|
|
EXPORTPARAMS => undef,
|
|
SHOREWALL_COMPILER => undef,
|
|
#
|
|
# Packet Disposition
|
|
#
|
|
MACLIST_DISPOSITION => undef,
|
|
TCP_FLAGS_DISPOSITION => undef,
|
|
BLACKLIST_DISPOSITION => undef,
|
|
);
|
|
|
|
#
|
|
# From parsing the capabilities file
|
|
#
|
|
%capabilities =
|
|
( NAT_ENABLED => undef,
|
|
MANGLE_ENABLED => undef,
|
|
MULTIPORT => undef,
|
|
XMULTIPORT => undef,
|
|
CONNTRACK_MATCH => undef,
|
|
USEPKTTYPE => undef,
|
|
POLICY_MATCH => undef,
|
|
PHYSDEV_MATCH => undef,
|
|
LENGTH_MATCH => undef,
|
|
IPRANGE_MATCH => undef,
|
|
RECENT_MATCH => undef,
|
|
OWNER_MATCH => undef,
|
|
IPSET_MATCH => undef,
|
|
CONNMARK => undef,
|
|
XCONNMARK => undef,
|
|
CONNMARK_MATCH => undef,
|
|
XCONNMARK_MATCH => undef,
|
|
RAW_TABLE => undef,
|
|
IPP2P_MATCH => undef,
|
|
CLASSIFY_TARGET => undef,
|
|
ENHANCED_REJECT => undef,
|
|
KLUDGEFREE => undef,
|
|
MARK => undef,
|
|
XMARK => undef,
|
|
MANGLE_FORWARD => undef,
|
|
COMMENTS => undef,
|
|
ADDRTYPE => undef,
|
|
CAPVERSION => undef,
|
|
);
|
|
#
|
|
# Capabilities
|
|
#
|
|
%capdesc = ( NAT_ENABLED => 'NAT',
|
|
MANGLE_ENABLED => 'Packet Mangling',
|
|
MULTIPORT => 'Multi-port Match' ,
|
|
XMULTIPORT => 'Extended Multi-port Match',
|
|
CONNTRACK_MATCH => 'Connection Tracking Match',
|
|
USEPKTTYPE => 'Packet Type Match',
|
|
POLICY_MATCH => 'Policy Match',
|
|
PHYSDEV_MATCH => 'Physdev Match',
|
|
LENGTH_MATCH => 'Packet length Match',
|
|
IPRANGE_MATCH => 'IP Range Match',
|
|
RECENT_MATCH => 'Recent Match',
|
|
OWNER_MATCH => 'Owner Match',
|
|
IPSET_MATCH => 'Ipset Match',
|
|
CONNMARK => 'CONNMARK Target',
|
|
XCONNMARK => 'Extended CONNMARK Target',
|
|
CONNMARK_MATCH => 'Connmark Match',
|
|
XCONNMARK_MATCH => 'Extended Connmark Match',
|
|
RAW_TABLE => 'Raw Table',
|
|
IPP2P_MATCH => 'IPP2P Match',
|
|
CLASSIFY_TARGET => 'CLASSIFY Target',
|
|
ENHANCED_REJECT => 'Extended Reject',
|
|
KLUDGEFREE => 'Repeat match',
|
|
MARK => 'MARK Target',
|
|
XMARK => 'Extended Mark Target',
|
|
MANGLE_FORWARD => 'Mangle FORWARD Chain',
|
|
COMMENTS => 'Comments',
|
|
ADDRTYPE => 'Address Type Match',
|
|
TCPMSS_MATCH => 'TCP MSS',
|
|
CAPVERSION => 'Capability Version',
|
|
);
|
|
#
|
|
# Directories to search for configuration files
|
|
#
|
|
@config_path = ();
|
|
#
|
|
# Stash away file references here when we encounter INCLUDE
|
|
#
|
|
@includestack = ();
|
|
#
|
|
# Allow nested opens
|
|
#
|
|
@openstack = ();
|
|
|
|
$currentfile = undef; # File handle reference
|
|
$currentfilename = ''; # File NAME
|
|
$currentlinenumber = 0; # Line number
|
|
|
|
$shorewall_dir = ''; #Shorewall Directory
|
|
}
|
|
|
|
INIT {
|
|
initialize;
|
|
}
|
|
|
|
#
|
|
# Issue a Warning Message
|
|
#
|
|
sub warning_message
|
|
{
|
|
my $lineinfo = $currentfile ? " : $currentfilename (line $currentlinenumber)" : '';
|
|
|
|
print STDERR " WARNING: @_$lineinfo\n";
|
|
}
|
|
|
|
#
|
|
# Issue fatal error message and die
|
|
#
|
|
sub fatal_error {
|
|
my $lineinfo = $currentfile ? " : $currentfilename (line $currentlinenumber)" : '';
|
|
|
|
die " ERROR: @_$lineinfo\n";
|
|
|
|
}
|
|
|
|
#
|
|
# Set $shorewall_dir
|
|
#
|
|
sub set_shorewall_dir( $ ) {
|
|
$shorewall_dir = shift;
|
|
}
|
|
|
|
#
|
|
# Search the CONFIG_PATH for the passed file
|
|
#
|
|
sub find_file($)
|
|
{
|
|
my $filename=$_[0];
|
|
|
|
return $filename if substr( $filename, 0, 1 ) eq '/';
|
|
|
|
my $directory;
|
|
|
|
for $directory ( @config_path ) {
|
|
my $file = "$directory$filename";
|
|
return $file if -f $file;
|
|
}
|
|
|
|
"$globals{CONFDIR}/$filename";
|
|
}
|
|
|
|
#
|
|
# 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 $line =~ /["'`\\]/;
|
|
|
|
my @line = split( /\s+/, $line, $maxcolumns + 1 );
|
|
|
|
fatal_error "Invalid $description entry (too few columns)" if @line < $mincolumns;
|
|
fatal_error "Invalid $description entry (too many columns)" if @line > $maxcolumns;
|
|
|
|
push @line, '-' while @line < $maxcolumns;
|
|
|
|
@line;
|
|
}
|
|
|
|
#
|
|
# Version of 'split_line' that handles COMMENT lines
|
|
#
|
|
sub split_line1( $$$ ) {
|
|
my ( $mincolumns, $maxcolumns, $description ) = @_;
|
|
|
|
fatal_error "Shorewall Configuration file entries may not contain double quotes, single back quotes or backslashes" if $line =~ /["`\\]/;
|
|
|
|
my @line = split( /\s+/, $line, $maxcolumns + 1);
|
|
|
|
return @line if $line[0] eq 'COMMENT';
|
|
|
|
fatal_error "Shorewall Configuration file entries may not contain single quotes" if $line =~ /'/;
|
|
|
|
fatal_error "Invalid $description entry (too few columns)" if @line < $mincolumns;
|
|
fatal_error "Invalid $description entry (too many columns)" if @line > $maxcolumns;
|
|
|
|
push @line, '-' while @line < $maxcolumns;
|
|
|
|
@line;
|
|
}
|
|
|
|
#
|
|
# When splitting a line in the rules file, don't pad out the columns with '-' if the first column contains one of these
|
|
#
|
|
|
|
my %no_pad = ( COMMENT => 0,
|
|
SECTION => 2 );
|
|
|
|
#
|
|
# Version of 'split_line' used on rules file entries
|
|
#
|
|
sub split_line2( $$$ ) {
|
|
my ( $mincolumns, $maxcolumns, $description ) = @_;
|
|
|
|
fatal_error "Shorewall Configuration file entries may not contain double quotes, single back quotes or backslashes" if $line =~ /["`\\]/;
|
|
|
|
my @line = split( /\s+/, $line, $maxcolumns + 1 );
|
|
|
|
my $first = $line[0];
|
|
my $columns = $no_pad{$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 $line =~ /'/;
|
|
|
|
fatal_error "Invalid $description entry (too few columns)" if @line < $mincolumns;
|
|
fatal_error "Invalid $description entry (too many columns)" if @line > $maxcolumns;
|
|
|
|
push @line, '-' while @line < $maxcolumns;
|
|
|
|
@line;
|
|
}
|
|
|
|
#
|
|
# 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];
|
|
|
|
fatal_error 'Internal Error in open_file()' if defined $currentfile;
|
|
|
|
do_open_file $fname if -f $fname && -s _;
|
|
}
|
|
|
|
#
|
|
# 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 ) {
|
|
close $currentfile;
|
|
|
|
my $arrayref = pop @includestack;
|
|
|
|
if ( $arrayref ) {
|
|
( $currentfile, $currentfilename, $currentlinenumber ) = @$arrayref;
|
|
} else {
|
|
$currentfile = undef;
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# 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};
|
|
|
|
my $arrayref = pop @includestack;
|
|
|
|
if ( $arrayref ) {
|
|
( $currentfile, $currentfilename, $currentlinenumber ) = @$arrayref;
|
|
} else {
|
|
$currentfile = undef;
|
|
}
|
|
}
|
|
|
|
#
|
|
# Read a line from the current include stack.
|
|
#
|
|
# - Ignore blank or comment-only lines.
|
|
# - Remove trailing comments.
|
|
# - Handle Line Continuation
|
|
# - Expand shell variables from $ENV.
|
|
# - Handle INCLUDE <filename>
|
|
#
|
|
|
|
sub read_a_line {
|
|
while ( $currentfile ) {
|
|
|
|
$line = '';
|
|
|
|
while ( my $nextline = <$currentfile> ) {
|
|
|
|
$currentlinenumber++;
|
|
|
|
chomp $nextline;
|
|
#
|
|
# Continuation
|
|
#
|
|
if ( substr( ( $line .= $nextline ), -1, 1 ) eq '\\' ) {
|
|
$line = substr( $line, 0, -1 );
|
|
next;
|
|
}
|
|
|
|
$line =~ s/#.*$//; # Remove Trailing Comments -- result might be a blank line
|
|
#
|
|
# Ignore ( concatenated ) Blank Lines
|
|
#
|
|
if ( $line =~ /^\s*$/ ) {
|
|
$line = '';
|
|
next;
|
|
}
|
|
|
|
$line =~ s/^\s+//; # Remove Leading white space
|
|
$line =~ s/\s+$//; # Remove Trailing white space
|
|
|
|
#
|
|
# Expand Shell Variables using %ENV
|
|
#
|
|
$line = join( '', $1 , ( $ENV{$2} || '' ) , $3 ) while $line =~ /^(.*?)\${([a-zA-Z]\w*)}(.*)$/;
|
|
$line = join( '', $1 , ( $ENV{$2} || '' ) , $3 ) while $line =~ /^(.*?)\$([a-zA-Z]\w*)(.*)$/;
|
|
|
|
if ( $line =~ /^INCLUDE\s/ ) {
|
|
|
|
my @line = split /\s+/, $line, 3;
|
|
|
|
fatal_error "Invalid INCLUDE command: $line" if @line != 2;
|
|
fatal_error "INCLUDEs nested too deeply: $line" if @includestack >= 4;
|
|
|
|
my $filename = find_file $line[1];
|
|
|
|
fatal_error "INCLUDE file $filename not found" unless ( -f $filename );
|
|
|
|
if ( -s _ ) {
|
|
push @includestack, [ $currentfile, $currentfilename, $currentlinenumber ];
|
|
$currentfile = undef;
|
|
do_open_file $filename;
|
|
}
|
|
|
|
$line = '';
|
|
} 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 ( $line = <$currentfile> ) {
|
|
$currentlinenumber++;
|
|
next if $line =~ /^\s*#/;
|
|
chomp $line;
|
|
next if $line =~ /^\s*$/;
|
|
$line =~ s/#.*$//; # Remove Trailing Comments -- result might be a blank line
|
|
$line =~ s/^\s+//; # Remove Leading white space
|
|
$line =~ s/\s+$//; # Remove Trailing white space
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
my %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' );
|
|
|
|
#
|
|
# Validate a log level -- Drop the trailing '!' that some fools think is important.
|
|
#
|
|
sub validate_level( $ ) {
|
|
my $level = $_[0];
|
|
|
|
if ( defined $level && $level ne '' ) {
|
|
$level =~ s/!$//;
|
|
my $value = $validlevels{$level};
|
|
return $value if defined $value;
|
|
return $level if $level =~ /^[0-7]$/;
|
|
fatal_error "Invalid log level ($level)";
|
|
}
|
|
|
|
'';
|
|
}
|
|
|
|
#
|
|
# Validate a log level and supply default
|
|
#
|
|
sub default_log_level( $$ ) {
|
|
my ( $level, $default ) = @_;
|
|
|
|
my $value = $config{$level};
|
|
|
|
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_capabilities() {
|
|
sub report_capability( $ ) {
|
|
my $cap = $_[0];
|
|
print " $capdesc{$cap}: ";
|
|
print $capabilities{$cap} ? "Available\n" : "Not Available\n";
|
|
}
|
|
|
|
print "Shorewall has detected the following capabilities:\n";
|
|
|
|
for my $cap ( sort { $capdesc{$a} cmp $capdesc{$b} } keys %capabilities ) {
|
|
report_capability $cap;
|
|
}
|
|
}
|
|
|
|
#
|
|
# Search the current PATH for the passed executable
|
|
#
|
|
sub mywhich( $ ) {
|
|
my $prog = $_[0];
|
|
|
|
for my $dir ( split /:/, $ENV{PATH} ) {
|
|
return "$dir/$prog" if -x "$dir/$prog";
|
|
}
|
|
|
|
'';
|
|
}
|
|
|
|
#
|
|
# Load the kernel modules defined in the 'modules' file.
|
|
#
|
|
sub load_kernel_modules( ) {
|
|
my $moduleloader = mywhich 'modprobe' ? 'modprobe' : 'insmod';
|
|
|
|
my $modulesdir = $config{MODULESDIR};
|
|
|
|
unless ( $modulesdir ) {
|
|
my $uname = `uname -r`;
|
|
fatal_error "The command 'uname -r' failed" unless $? == 0;
|
|
chomp $uname;
|
|
$modulesdir = "/lib/modules/$uname/kernel/net/ipv4/netfilter:/lib/modules/$uname/kernel/net/netfilter";
|
|
}
|
|
|
|
my @moduledirectories = split /:/, $modulesdir;
|
|
|
|
if ( @moduledirectories && open_file 'modules' ) {
|
|
my %loadedmodules;
|
|
|
|
progress_message "Loading Modules...";
|
|
|
|
open LSMOD , '-|', 'lsmod' or fatal_error "Can't run lsmod";
|
|
|
|
while ( $line = <LSMOD> ) {
|
|
my $module = ( split( /\s+/, $line, 2 ) )[0];
|
|
$loadedmodules{$module} = 1 unless $module eq 'Module'
|
|
}
|
|
|
|
close LSMOD;
|
|
|
|
$config{MODULE_SUFFIX} = 'o gz ko o.gz ko.gz' unless $config{MODULES_SUFFIX};
|
|
|
|
my @suffixes = split /\s+/ , $config{MODULE_SUFFIX};
|
|
|
|
while ( read_a_line ) {
|
|
fatal_error "Invalid modules file entry" unless ( $line =~ /^loadmodule\s+([a-zA-Z]\w*)\s*(.*)$/ );
|
|
my ( $module, $arguments ) = ( $1, $2 );
|
|
unless ( $loadedmodules{ $module } ) {
|
|
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;
|
|
}
|
|
|
|
#
|
|
# Determine which optional facilities are supported by iptables/netfilter
|
|
#
|
|
sub determine_capabilities() {
|
|
|
|
my $iptables = $config{IPTABLES};
|
|
my $pid = $$;
|
|
my $sillyname = "fooX$pid";
|
|
|
|
$capabilities{NAT_ENABLED} = qt( "$iptables -t nat -L -n" );
|
|
$capabilities{MANGLE_ENABLED} = qt( "$iptables -t mangle -L -n" );
|
|
|
|
qt( "$iptables -N $sillyname" );
|
|
|
|
$capabilities{CONNTRACK_MATCH} = qt( "$iptables -A $sillyname -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT" );
|
|
$capabilities{MULTIPORT} = qt( "$iptables -A $sillyname -p tcp -m multiport --dports 21,22 -j ACCEPT" );
|
|
$capabilities{XMULTIPORT} = qt( "$iptables -A $sillyname -p tcp -m multiport --dports 21:22 -j ACCEPT" );
|
|
$capabilities{POLICY_MATCH} = qt( "$iptables -A $sillyname -m policy --pol ipsec --mode tunnel --dir in -j ACCEPT" );
|
|
$capabilities{PHYSDEV_MATCH} = qt( "$iptables -A $sillyname -m physdev --physdev-in eth0 -j ACCEPT" );
|
|
|
|
if ( qt( "$iptables -A $sillyname -m iprange --src-range 192.168.1.5-192.168.1.124 -j ACCEPT" ) ) {
|
|
$capabilities{IPRANGE_MATCH} = 1;
|
|
unless ( $capabilities{KLUDGEFREE} ) {
|
|
$capabilities{KLUDGEFREE} = qt( "$iptables -A $sillyname -m iprange --src-range 192.168.1.5-192.168.1.124 -m iprange --dst-range 192.168.1.5-192.168.1.124 -j ACCEPT" );
|
|
}
|
|
}
|
|
|
|
$capabilities{RECENT_MATCH} = qt( "$iptables -A $sillyname -m recent --update -j ACCEPT" );
|
|
$capabilities{OWNER_MATCH} = qt( "$iptables -A $sillyname -m owner --uid-owner 0 -j ACCEPT" );
|
|
|
|
if ( qt( "$iptables -A $sillyname -m connmark --mark 2 -j ACCEPT" )) {
|
|
$capabilities{CONNMARK_MATCH} = 1;
|
|
$capabilities{XCONNMARK_MATCH} = qt( "$iptables -A $sillyname -m connmark --mark 2/0xFF -j ACCEPT" );
|
|
}
|
|
|
|
$capabilities{IPP2P_MATCH} = qt( "$iptables -A $sillyname -p tcp -m ipp2p --ipp2p -j ACCEPT" );
|
|
$capabilities{LENGTH_MATCH} = qt( "$iptables -A $sillyname -m length --length 10:20 -j ACCEPT" );
|
|
$capabilities{ENHANCED_REJECT} = qt( "$iptables -A $sillyname -j REJECT --reject-with icmp-host-prohibited" );
|
|
$capabilities{COMMENTS} = qt( qq($iptables -A $sillyname -j ACCEPT -m comment --comment "This is a comment" ) );
|
|
|
|
if ( $capabilities{MANGLE_ENABLED} ) {
|
|
qt( "$iptables -t mangle -N $sillyname" );
|
|
|
|
if ( qt( "$iptables -t mangle -A $sillyname -j MARK --set-mark 1" ) ) {
|
|
$capabilities{MARK} = 1;
|
|
$capabilities{XMARK} = qt( "$iptables -t mangle -A $sillyname -j MARK --and-mark 0xFF" );
|
|
}
|
|
|
|
if ( qt( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark" ) ) {
|
|
$capabilities{CONNMARK} = 1;
|
|
$capabilities{XCONNMARK} = qt( "$iptables -t mangle -A $sillyname -j CONNMARK --save-mark --mask 0xFF" );
|
|
}
|
|
|
|
$capabilities{CLASSIFY_TARGET} = qt( "$iptables -t mangle -A $sillyname -j CLASSIFY --set-class 1:1" );
|
|
qt( "$iptables -t mangle -F $sillyname" );
|
|
qt( "$iptables -t mangle -X $sillyname" );
|
|
|
|
$capabilities{MANGLE_FORWARD} = qt( "$iptables -t mangle -L FORWARD -n" );
|
|
}
|
|
|
|
$capabilities{RAW_TABLE} = qt( "$iptables -t raw -L -n" );
|
|
|
|
if ( mywhich 'ipset' ) {
|
|
qt( "ipset -X $sillyname" );
|
|
|
|
if ( qt( "ipset -N $sillyname iphash" ) ) {
|
|
if ( qt( "$iptables -A $sillyname -m set --set $sillyname src -j ACCEPT" ) ) {
|
|
qt( "$iptables -D $sillyname -m set --set $sillyname src -j ACCEPT" );
|
|
$capabilities{IPSET_MATCH} = 1;
|
|
}
|
|
|
|
qt( "ipset -X $sillyname" );
|
|
}
|
|
}
|
|
|
|
$capabilities{USEPKTTYPE} = qt( "$iptables -A $sillyname -m pkttype --pkt-type broadcast -j ACCEPT" );
|
|
$capabilities{ADDRTYPE} = qt( "$iptables -A $sillyname -m addrtype --src-type BROADCAST -j ACCEPT" );
|
|
$capabilities{TCPMSS_MATCH} = qt( "$iptables -A $sillyname -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1000:1500 -j ACCEPT" );
|
|
|
|
qt( "$iptables -F $sillyname" );
|
|
qt( "$iptables -X $sillyname" );
|
|
|
|
$capabilities{CAPVERSION} = $globals{CAPVERSION};
|
|
}
|
|
|
|
#
|
|
# Require the passed capability
|
|
#
|
|
sub require_capability( $$$ ) {
|
|
my ( $capability, $description, $singular ) = @_;
|
|
|
|
fatal_error "$description require${singular} $capdesc{$capability} in your kernel and iptables"
|
|
unless $capabilities{$capability};
|
|
}
|
|
|
|
#
|
|
# Set default config path
|
|
#
|
|
sub ensure_config_path() {
|
|
|
|
my $f = "$globals{SHAREDIR}/configpath";
|
|
|
|
$globals{CONFDIR} = '/usr/share/shorewall/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 ( $line =~ /^\s*([a-zA-Z]\w*)=(.*?)\s*$/ ) {
|
|
my ($var, $val) = ($1, $2);
|
|
$config{$var} = ( $val =~ /\"([^\"]*)\"$/ ? $1 : $val ) if exists $config{$var};
|
|
} else {
|
|
fatal_error "Unrecognized entry";
|
|
}
|
|
}
|
|
|
|
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 .= '/' unless $shorewall_dir =~ m|/$|;
|
|
unshift @config_path, $shorewall_dir if $shorewall_dir ne $config_path[0];
|
|
}
|
|
}
|
|
|
|
#
|
|
# Small functions called by get_configuration. We separate them so profiling is more useful
|
|
#
|
|
sub process_shorewall_conf() {
|
|
my $file = find_file 'shorewall.conf';
|
|
|
|
if ( -f $file ) {
|
|
if ( -r _ ) {
|
|
open_file $file;
|
|
|
|
while ( read_a_line ) {
|
|
if ( $line =~ /^\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!";
|
|
}
|
|
}
|
|
|
|
sub get_capabilities( $ ) {
|
|
my $export = $_[0];
|
|
|
|
if ( ! $export && $> == 0 ) { # $> == $EUID
|
|
unless ( $config{IPTABLES} ) {
|
|
fatal_error "Can't find iptables executable" unless $config{IPTABLES} = mywhich 'iptables';
|
|
} else {
|
|
fatal_error "\$IPTABLES=$config{IPTABLES} does not exist or is not executable" unless -x $config{IPTABLES};
|
|
}
|
|
|
|
load_kernel_modules;
|
|
|
|
unless ( open_file 'capabilities' ) {
|
|
determine_capabilities;
|
|
}
|
|
} else {
|
|
unless ( open_file 'capabilities' ) {
|
|
fatal_error "The -e flag requires a capabilities file" if $export;
|
|
fatal_error "Compiling under non-root uid requires a capabilities file";
|
|
}
|
|
}
|
|
|
|
#
|
|
# If we successfully called open_file above, then this loop will read the capabilities file.
|
|
# Otherwise, the first call to read_a_line() below will return false
|
|
#
|
|
while ( read_a_line1 ) {
|
|
if ( $line =~ /^([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 Shorewall version $globals{VERSION}" unless $capabilities{CAPVERSION} >= $globals{CAPVERSION};
|
|
} else {
|
|
warning_message "Your capabilities file may not contain all of the capabilities defined by Shorewall version $globals{VERSION}";
|
|
}
|
|
}
|
|
|
|
#
|
|
# - Read the shorewall.conf file
|
|
# - Read the capabilities file, if any
|
|
# - establish global hashes %config , %globals and %capabilities
|
|
#
|
|
sub get_configuration( $ ) {
|
|
|
|
my $export = $_[0];
|
|
|
|
ensure_config_path;
|
|
|
|
process_shorewall_conf;
|
|
|
|
ensure_config_path;
|
|
|
|
default 'PATH' , '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin';
|
|
|
|
default 'MODULE_PREFIX', 'o gz ko o.gz ko.gz';
|
|
|
|
get_capabilities( $export );
|
|
|
|
$globals{ORIGINAL_POLICY_MATCH} = $capabilities{POLICY_MATCH};
|
|
|
|
if ( $config{LOGRATE} || $config{LOGBURST} ) {
|
|
$globals{LOGLIMIT} = '-m limit ';
|
|
$globals{LOGLIMIT} .= "--limit $config{LOGRATE} " if $config{LOGRATE};
|
|
$globals{LOGLIMIT} .= "--limit-burst $config{LOGBURST} " if $config{LOGBURST};
|
|
} else {
|
|
$globals{LOGLIMIT} = '';
|
|
}
|
|
|
|
check_trivalue ( 'IP_FORWARDING', 'on' );
|
|
check_trivalue ( 'ROUTE_FILTER', '' );
|
|
check_trivalue ( 'LOG_MARTIANS', '' );
|
|
|
|
default_yes_no 'ADD_IP_ALIASES' , 'Yes';
|
|
default_yes_no 'ADD_SNAT_ALIASES' , '';
|
|
default_yes_no 'DETECT_DNAT_IPADDRS' , '';
|
|
default_yes_no 'DETECT_DNAT_IPADDRS' , '';
|
|
default_yes_no 'CLEAR_TC' , 'Yes';
|
|
|
|
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 'RETAIN_ALIASES' , '';
|
|
}
|
|
|
|
default_yes_no 'ADMINISABSENTMINDED' , '';
|
|
default_yes_no 'BLACKLISTNEWONLY' , '';
|
|
default_yes_no 'DISABLE_IPV6' , '';
|
|
default_yes_no 'DYNAMIC_ZONES' , '';
|
|
|
|
fatal_error "DYNAMIC_ZONES=Yes is incompatible with the -e option" if $config{DYNAMIC_ZONES} && $export;
|
|
|
|
default_yes_no 'BRIDGING' , '';
|
|
|
|
fatal_error 'BRIDGING=Yes is not supported by Shorewall-perl' . $globals{VERSION} if $config{BRIDGING};
|
|
|
|
default_yes_no 'STARTUP_ENABLED' , 'Yes';
|
|
default_yes_no 'DELAYBLACKLISTLOAD' , '';
|
|
|
|
warning_message 'DELAYBLACKLISTLOAD=Yes is not supported by Shorewall-perl ' . $globals{VERSION} if $config{DELAYBLACKLISTLOAD};
|
|
|
|
default_yes_no 'LOGTAGONLY' , '';
|
|
default_yes_no 'RFC1918_STRICT' , '';
|
|
default_yes_no 'SAVE_IPSETS' , '';
|
|
|
|
warning_message 'SAVE_IPSETS=Yes is not supported by Shorewall-perl ' . $globals{VERSION} if $config{SAVE_IPSETS};
|
|
|
|
default_yes_no 'MAPOLDACTIONS' , '';
|
|
|
|
warning_message 'MAPOLDACTIONS=Yes is not supported by Shorewall-perl ' . $globals{VERSION} if $config{MAPOLDACTIONS};
|
|
|
|
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';
|
|
|
|
warning_message 'USE_ACTIONS=No is not supported by Shorewall-perl ' . $globals{VERSION} unless $config{USE_ACTIONS};
|
|
|
|
default_yes_no 'EXPORTPARAMS' , '';
|
|
default_yes_no 'MARK_IN_FORWARD_CHAIN' , '';
|
|
|
|
$capabilities{XCONNMARK} = '' unless $capabilities{XCONNMARK_MATCH} and $capabilities{XMARK};
|
|
|
|
default 'BLACKLIST_DISPOSITION' , 'DROP';
|
|
|
|
default_log_level 'BLACKLIST_LOGLEVEL', '';
|
|
default_log_level 'MACLIST_LOG_LEVEL', '';
|
|
default_log_level 'TCP_FLAGS_LOG_LEVEL', '';
|
|
default_log_level 'RFC1918_LOG_LEVEL', 6;
|
|
default_log_level 'SMURF_LOG_LEVEL', '';
|
|
default_log_level 'LOGALLNEW', '';
|
|
|
|
my $val;
|
|
|
|
$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' , 'Internal';
|
|
|
|
$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 ne 'internal' ) {
|
|
fatal_error "Invalid value ($config{TC_ENABLED}) for TC_ENABLED" unless $val eq 'no';
|
|
$config{TC_ENABLED} = '';
|
|
}
|
|
|
|
default 'RESTOREFILE' , 'restore';
|
|
default 'DROP_DEFAULT' , 'Drop';
|
|
default 'REJECT_DEFAULT' , 'Reject';
|
|
default 'QUEUE_DEFAULT' , 'none';
|
|
default 'ACCEPT_DEFAULT' , 'none';
|
|
default 'OPTIMIZE' , 0;
|
|
default 'IPSECFILE' , 'zones';
|
|
|
|
fatal_error 'IPSECFILE=ipsec is not supported by Shorewall-perl ' . $globals{VERSION} unless $config{IPSECFILE} eq 'zones';
|
|
|
|
for my $default qw/DROP_DEFAULT REJECT_DEFAULT QUEUE_DEFAULT ACCEPT_DEFAULT/ {
|
|
$config{$default} = 'none' if "\L$config{$default}" eq 'none';
|
|
}
|
|
|
|
$val = $config{OPTIMIZE};
|
|
|
|
fatal_error "Invalid OPTIMIZE value ($val)" unless ( $val eq '0' ) || ( $val eq '1' );
|
|
|
|
fatal_error "Invalid IPSECFILE value ($config{IPSECFILE}" unless $config{IPSECFILE} eq 'zones';
|
|
|
|
$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} );
|
|
};
|
|
|
|
die $@ if $@;
|
|
|
|
fatal_error "LOCKFILE=$config{LOCKFILE}: Directory $dir does not exist" unless -d $dir;
|
|
} else {
|
|
$config{LOCKFILE} = '';
|
|
}
|
|
}
|
|
|
|
#
|
|
# The values of the options in @propagateconfig are copied to the object file in OPTION=<value> format.
|
|
#
|
|
sub propagateconfig() {
|
|
for my $option ( @propagateconfig ) {
|
|
my $value = $config{$option} || '';
|
|
emit "$option=\"$value\"";
|
|
}
|
|
|
|
for my $option ( @propagateenv ) {
|
|
my $value = $globals{$option} || '';
|
|
emit "$option=\"$value\"";
|
|
}
|
|
}
|
|
|
|
#
|
|
# Add a shell script file to the output script -- Return true if the
|
|
# file exists and is not in /usr/share/shorewall/.
|
|
#
|
|
sub append_file( $ ) {
|
|
my $user_exit = find_file $_[0];
|
|
my $result = 0;
|
|
|
|
unless ( $user_exit =~ /^($globals{SHAREDIR})/ ) {
|
|
if ( -f $user_exit ) {
|
|
$result = 1;
|
|
save_progress_message "Processing $user_exit ...";
|
|
copy1 $user_exit;
|
|
}
|
|
}
|
|
|
|
$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...";
|
|
|
|
unless (my $return = eval `cat $file` ) {
|
|
fatal_error "Couldn't parse $file: $@" if $@;
|
|
fatal_error "Couldn't do $file: $!" unless defined $return;
|
|
fatal_error "Couldn't run $file";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub run_user_exit1( $ ) {
|
|
my $file = find_file $_[0];
|
|
|
|
if ( -f $file ) {
|
|
progress_message "Processing $file...";
|
|
#
|
|
# File may be empty -- in which case eval would fail
|
|
#
|
|
push_open $file;
|
|
|
|
if ( read_a_line ) {
|
|
close_file;
|
|
|
|
unless (my $return = eval `cat $file` ) {
|
|
fatal_error "Couldn't parse $file: $@" if $@;
|
|
fatal_error "Couldn't do $file: $!" unless defined $return;
|
|
fatal_error "Couldn't run $file";
|
|
}
|
|
}
|
|
|
|
pop_open;
|
|
}
|
|
}
|
|
|
|
sub run_user_exit2( $$ ) {
|
|
my ($file, $chainref) = ( find_file $_[0], $_[1] );
|
|
|
|
if ( -f $file ) {
|
|
progress_message "Processing $file...";
|
|
#
|
|
# File may be empty -- in which case eval would fail
|
|
#
|
|
push_open $file;
|
|
|
|
if ( read_a_line ) {
|
|
close_file;
|
|
|
|
unless (my $return = eval `cat $file` ) {
|
|
fatal_error "Couldn't parse $file: $@" if $@;
|
|
fatal_error "Couldn't do $file: $!" unless defined $return;
|
|
fatal_error "Couldn't run $file";
|
|
}
|
|
}
|
|
|
|
pop_open;
|
|
|
|
}
|
|
}
|
|
|
|
#
|
|
# 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 $value ne '';
|
|
}
|
|
|
|
sub conditionally_add_option1( $ ) {
|
|
my $option = $_[0];
|
|
|
|
my $value = $config{$option};
|
|
|
|
emit "$option=\"$value\"" if $value;
|
|
}
|
|
|
|
create_temp_aux_config;
|
|
|
|
emit join ( '', "#\n# Shorewall auxiliary configuration file created by Shorewall-perl version ", $globals{VERSION}, ' - ' , localtime , "\n#" );
|
|
|
|
for my $option qw(VERBOSITY LOGFILE LOGFORMAT IPTABLES PATH SHOREWALL_SHELL SUBSYSLOCK LOCKFILE RESTOREFILE SAVE_IPSETS) {
|
|
conditionally_add_option $option;
|
|
}
|
|
|
|
conditionally_add_option1 'TC_ENABLED';
|
|
|
|
finalize_aux_config;
|
|
|
|
}
|
|
|
|
1;
|