mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-26 17:43:15 +01:00
d9bd01d720
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@9123 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
1090 lines
27 KiB
Perl
1090 lines
27 KiB
Perl
#! /usr/bin/perl -w
|
|
#
|
|
# The Shoreline Firewall4 (Shorewall-perl) Packet Filtering Firewall Compiler - V4.2
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
#
|
|
# (c) 2007,2008 - 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
|
|
package Shorewall::Compiler;
|
|
require Exporter;
|
|
use Shorewall::Config qw(:DEFAULT :internal);
|
|
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
use Shorewall::Zones;
|
|
use Shorewall::Policy;
|
|
use Shorewall::Nat;
|
|
use Shorewall::Providers;
|
|
use Shorewall::Tc;
|
|
use Shorewall::Tunnels;
|
|
use Shorewall::Actions;
|
|
use Shorewall::Accounting;
|
|
use Shorewall::Rules;
|
|
use Shorewall::Proc;
|
|
use Shorewall::Proxyarp;
|
|
use Shorewall::IPAddrs;
|
|
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT = qw( compiler EXPORT TIMESTAMP DEBUG );
|
|
our @EXPORT_OK = qw( $export );
|
|
our $VERSION = 4.2.4;
|
|
|
|
our $export;
|
|
|
|
our $test;
|
|
|
|
our $reused = 0;
|
|
|
|
our $family = F_IPV4;
|
|
|
|
use constant { EXPORT => 0x01 ,
|
|
TIMESTAMP => 0x02 ,
|
|
DEBUG => 0x04 };
|
|
|
|
#
|
|
# Reinitilize the package-globals in the other modules
|
|
#
|
|
sub reinitialize() {
|
|
Shorewall::Config::initialize($family);
|
|
Shorewall::Chains::initialize ($family);
|
|
Shorewall::Zones::initialize ($family);
|
|
Shorewall::Policy::initialize;
|
|
Shorewall::Nat::initialize;
|
|
Shorewall::Providers::initialize($family);
|
|
Shorewall::Tc::initialize($family);
|
|
Shorewall::Actions::initialize( $family );
|
|
Shorewall::Accounting::initialize;
|
|
Shorewall::Rules::initialize($family);
|
|
Shorewall::Proxyarp::initialize($family);
|
|
Shorewall::IPAddrs::initialize($family);
|
|
}
|
|
|
|
#
|
|
# First stage of script generation.
|
|
#
|
|
# Copy the prog.header to the generated script.
|
|
# Generate the various user-exit jacket functions.
|
|
# Generate the 'initialize()' function.
|
|
#
|
|
# Note: This function is not called when $command eq 'check'. So it must have no side effects other
|
|
# than those related to writing to the object file.
|
|
|
|
sub generate_script_1() {
|
|
|
|
my $date = localtime;
|
|
|
|
if ( $test ) {
|
|
emit "#!/bin/sh\n#\n# Compiled firewall script generated by Shorewall-perl\n#";
|
|
} else {
|
|
emit "#!/bin/sh\n#\n# Compiled firewall script generated by Shorewall-perl $globals{VERSION} - $date\n#";
|
|
if ( $family == F_IPV4 ) {
|
|
copy $globals{SHAREDIRPL} . 'prog.header';
|
|
} else {
|
|
copy $globals{SHAREDIRPL} . 'prog.header6';
|
|
}
|
|
}
|
|
|
|
for my $exit qw/init isusable start tcclear started stop stopped clear refresh refreshed/ {
|
|
emit "\nrun_${exit}_exit() {";
|
|
push_indent;
|
|
append_file $exit or emit 'true';
|
|
pop_indent;
|
|
emit '}';
|
|
}
|
|
|
|
emit ( '',
|
|
'#',
|
|
'# This function initializes the global variables used by the program',
|
|
'#',
|
|
'initialize()',
|
|
'{',
|
|
' #',
|
|
' # These variables are required by the library functions called in this script',
|
|
' #'
|
|
);
|
|
|
|
push_indent;
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
if ( $export ) {
|
|
emit ( 'SHAREDIR=/usr/share/shorewall-lite',
|
|
'CONFDIR=/etc/shorewall-lite',
|
|
'PRODUCT="Shorewall Lite"'
|
|
);
|
|
} else {
|
|
emit ( 'SHAREDIR=/usr/share/shorewall',
|
|
'CONFDIR=/etc/shorewall',
|
|
'PRODUCT=\'Shorewall\'',
|
|
);
|
|
}
|
|
} else {
|
|
if ( $export ) {
|
|
emit ( 'SHAREDIR=/usr/share/shorewall6-lite',
|
|
'CONFDIR=/etc/shorewall6-lite',
|
|
'PRODUCT="Shorewall6 Lite"'
|
|
);
|
|
} else {
|
|
emit ( 'SHAREDIR=/usr/share/shorewall6',
|
|
'CONFDIR=/etc/shorewall6',
|
|
'PRODUCT=\'Shorewall6\'',
|
|
);
|
|
}
|
|
}
|
|
|
|
emit( '[ -f ${CONFDIR}/vardir ] && . ${CONFDIR}/vardir' );
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
if ( $export ) {
|
|
emit ( 'CONFIG_PATH="/etc/shorewall-lite:/usr/share/shorewall-lite"' ,
|
|
'[ -n "${VARDIR:=/var/lib/shorewall-lite}" ]' );
|
|
} else {
|
|
emit ( qq(CONFIG_PATH="$config{CONFIG_PATH}") ,
|
|
'[ -n "${VARDIR:=/var/lib/shorewall}" ]' );
|
|
}
|
|
} else {
|
|
if ( $export ) {
|
|
emit ( 'CONFIG_PATH="/etc/shorewall6-lite:/usr/share/shorewall6-lite"' ,
|
|
'[ -n "${VARDIR:=/var/lib/shorewall6-lite}" ]' );
|
|
} else {
|
|
emit ( qq(CONFIG_PATH="$config{CONFIG_PATH}") ,
|
|
'[ -n "${VARDIR:=/var/lib/shorewall6}" ]' );
|
|
}
|
|
}
|
|
|
|
emit 'TEMPFILE=';
|
|
|
|
propagateconfig;
|
|
|
|
my @dont_load = split_list $config{DONT_LOAD}, 'module';
|
|
|
|
emit ( '[ -n "${COMMAND:=restart}" ]',
|
|
'[ -n "${VERBOSE:=0}" ]',
|
|
qq([ -n "\${RESTOREFILE:=$config{RESTOREFILE}}" ]),
|
|
'[ -n "$LOGFORMAT" ] || LOGFORMAT="Shorewall:%s:%s:"' );
|
|
|
|
emit ( qq(VERSION="$globals{VERSION}") ) unless $test;
|
|
|
|
emit ( qq(PATH="$config{PATH}") ,
|
|
'TERMINATOR=fatal_error' ,
|
|
qq(DONT_LOAD="@dont_load") ,
|
|
qq(STARTUP_LOG="$config{STARTUP_LOG}") ,
|
|
"LOG_VERBOSE=$config{LOG_VERBOSITY}" ,
|
|
''
|
|
);
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
if ( $config{IPTABLES} ) {
|
|
emit( qq(IPTABLES="$config{IPTABLES}"),
|
|
'[ -x "$IPTABLES" ] || startup_error "IPTABLES=$IPTABLES does not exist or is not executable"',
|
|
);
|
|
} else {
|
|
emit( '[ -z "$IPTABLES" ] && IPTABLES=$(mywhich iptables) # /sbin/shorewall exports IPTABLES',
|
|
'[ -n "$IPTABLES" -a -x "$IPTABLES" ] || startup_error "Can\'t find iptables executable"'
|
|
);
|
|
}
|
|
|
|
emit( 'IPTABLES_RESTORE=${IPTABLES}-restore',
|
|
'[ -x "$IPTABLES_RESTORE" ] || startup_error "$IPTABLES_RESTORE does not exist or is not executable"' );
|
|
} else {
|
|
if ( $config{IP6TABLES} ) {
|
|
emit( qq(IP6TABLES="$config{IP6TABLES}"),
|
|
'[ -x "$IP6TABLES" ] || startup_error "IP6TABLES=$IP6TABLES does not exist or is not executable"',
|
|
);
|
|
} else {
|
|
emit( '[ -z "$IP6TABLES" ] && IP6TABLES=$(mywhich ip6tables) # /sbin/shorewall6 exports IP6TABLES',
|
|
'[ -n "$IP6TABLES" -a -x "$IP6TABLES" ] || startup_error "Can\'t find ip6tables executable"'
|
|
);
|
|
}
|
|
|
|
emit( 'IP6TABLES_RESTORE=${IP6TABLES}-restore',
|
|
'[ -x "$IP6TABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' );
|
|
}
|
|
|
|
append_file 'params' if $config{EXPORTPARAMS};
|
|
|
|
emit ( '',
|
|
"STOPPING=",
|
|
'',
|
|
'#',
|
|
'# The library requires that ${VARDIR} exist',
|
|
'#',
|
|
'[ -d ${VARDIR} ] || mkdir -p ${VARDIR}'
|
|
);
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
emit ( '',
|
|
'#',
|
|
'# Recent kernels are difficult to configure -- we see state match omitted a lot so we check for it here',
|
|
'#',
|
|
'qt1 $IPTABLES -N foox1234',
|
|
'qt1 $IPTABLES -A foox1234 -m state --state ESTABLISHED,RELATED -j ACCEPT',
|
|
'result=$?',
|
|
'qt1 $IPTABLES -F foox1234',
|
|
'qt1 $IPTABLES -X foox1234',
|
|
'[ $result = 0 ] || startup_error "Your kernel/iptables do not include state match support. No version of Shorewall will run on this system"',
|
|
'' );
|
|
} else {
|
|
emit ( '',
|
|
'#',
|
|
'# Recent kernels are difficult to configure -- we see state match omitted a lot so we check for it here',
|
|
'#',
|
|
'qt1 $IP6TABLES -N foox1234',
|
|
'qt1 $IP6TABLES -A foox1234 -m state --state ESTABLISHED,RELATED -j ACCEPT',
|
|
'result=$?',
|
|
'qt1 $IP6TABLES -F foox1234',
|
|
'qt1 $IP6TABLES -X foox1234',
|
|
'[ $result = 0 ] || startup_error "Your kernel/ip6tables do not include state match support. No version of Shorewall6 will run on this system"',
|
|
'' );
|
|
}
|
|
|
|
pop_indent;
|
|
|
|
emit "}\n"; # End of initialize()
|
|
|
|
}
|
|
|
|
sub compile_stop_firewall() {
|
|
|
|
emit <<'EOF';
|
|
#
|
|
# Stop/restore the firewall after an error or because of a 'stop' or 'clear' command
|
|
#
|
|
stop_firewall() {
|
|
EOF
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
emit( ' deletechain() {',
|
|
' qt $IPTABLES -L $1 -n && qt $IPTABLES -F $1 && qt $IPTABLES -X $1' );
|
|
} else {
|
|
emit( ' deletechain() {',
|
|
' qt $IP6TABLES -L $1 -n && qt $IP6TABLES -F $1 && qt $IP6TABLES -X $1' );
|
|
}
|
|
|
|
emit <<'EOF';
|
|
}
|
|
|
|
deleteallchains() {
|
|
do_iptables -F
|
|
do_iptables -X
|
|
}
|
|
|
|
setcontinue() {
|
|
do_iptables -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT
|
|
}
|
|
|
|
delete_nat() {
|
|
do_iptables -t nat -F
|
|
do_iptables -t nat -X
|
|
|
|
if [ -f ${VARDIR}/nat ]; then
|
|
while read external interface; do
|
|
del_ip_addr $external $interface
|
|
done < ${VARDIR}/nat
|
|
|
|
rm -f ${VARDIR}/nat
|
|
fi
|
|
}
|
|
|
|
case $COMMAND in
|
|
stop|clear|restore)
|
|
;;
|
|
*)
|
|
set +x
|
|
|
|
case $COMMAND in
|
|
start)
|
|
logger -p kern.err "ERROR:$PRODUCT start failed"
|
|
;;
|
|
restart)
|
|
logger -p kern.err "ERROR:$PRODUCT restart failed"
|
|
;;
|
|
restore)
|
|
logger -p kern.err "ERROR:$PRODUCT restore failed"
|
|
;;
|
|
esac
|
|
|
|
if [ "$RESTOREFILE" = NONE ]; then
|
|
COMMAND=clear
|
|
clear_firewall
|
|
echo "$PRODUCT Cleared"
|
|
|
|
kill $$
|
|
exit 2
|
|
else
|
|
RESTOREPATH=${VARDIR}/$RESTOREFILE
|
|
|
|
if [ -x $RESTOREPATH ]; then
|
|
|
|
if [ -x ${RESTOREPATH}-ipsets ]; then
|
|
progress_message2 Restoring Ipsets...
|
|
#
|
|
# We must purge iptables to be sure that there are no
|
|
# references to ipsets
|
|
#
|
|
for table in mangle nat filter; do
|
|
do_iptables -t $table -F
|
|
do_iptables -t $table -X
|
|
done
|
|
|
|
${RESTOREPATH}-ipsets
|
|
fi
|
|
|
|
echo Restoring ${PRODUCT:=Shorewall}...
|
|
|
|
if $RESTOREPATH restore; then
|
|
echo "$PRODUCT restored from $RESTOREPATH"
|
|
set_state "Started"
|
|
else
|
|
set_state "Unknown"
|
|
fi
|
|
|
|
kill $$
|
|
exit 2
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
set_state "Stopping"
|
|
|
|
STOPPING="Yes"
|
|
|
|
TERMINATOR=
|
|
|
|
deletechain shorewall
|
|
|
|
run_stop_exit
|
|
EOF
|
|
|
|
if ( $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED} ) {
|
|
emit <<'EOF';
|
|
run_iptables -t mangle -F
|
|
run_iptables -t mangle -X
|
|
for chain in PREROUTING INPUT FORWARD POSTROUTING; do
|
|
qt1 $IPTABLES -t mangle -P $chain ACCEPT
|
|
done
|
|
EOF
|
|
}
|
|
|
|
if ( $capabilities{RAW_TABLE} ) {
|
|
if ( $family == F_IPV4 ) {
|
|
emit <<'EOF';
|
|
run_iptables -t raw -F
|
|
run_iptables -t raw -X
|
|
for chain in PREROUTING OUTPUT; do
|
|
qt1 $IPTABLES -t raw -P $chain ACCEPT
|
|
done
|
|
EOF
|
|
} else {
|
|
emit <<'EOF';
|
|
run_iptables -t raw -F
|
|
run_iptables -t raw -X
|
|
for chain in PREROUTING OUTPUT; do
|
|
qt1 $IP6TABLES -t raw -P $chain ACCEPT
|
|
done
|
|
EOF
|
|
}
|
|
}
|
|
|
|
if ( $capabilities{NAT_ENABLED} ) {
|
|
emit <<'EOF';
|
|
delete_nat
|
|
for chain in PREROUTING POSTROUTING OUTPUT; do
|
|
qt1 $IPTABLES -t nat -P $chain ACCEPT
|
|
done
|
|
EOF
|
|
}
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
emit <<'EOF';
|
|
if [ -f ${VARDIR}/proxyarp ]; then
|
|
while read address interface external haveroute; do
|
|
qt arp -i $external -d $address pub
|
|
[ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface
|
|
f=/proc/sys/net/ipv4/conf/$interface/proxy_arp
|
|
[ -f $f ] && echo 0 > $f
|
|
done < ${VARDIR}/proxyarp
|
|
fi
|
|
|
|
rm -f ${VARDIR}/proxyarp
|
|
EOF
|
|
}
|
|
|
|
push_indent;
|
|
|
|
emit 'delete_tc1' if $config{CLEAR_TC};
|
|
|
|
emit( 'undo_routing',
|
|
'restore_default_route'
|
|
);
|
|
|
|
my $criticalhosts = process_criticalhosts;
|
|
|
|
if ( @$criticalhosts ) {
|
|
if ( $config{ADMINISABSENTMINDED} ) {
|
|
emit ( 'for chain in INPUT OUTPUT; do',
|
|
' setpolicy $chain ACCEPT',
|
|
'done',
|
|
'',
|
|
'setpolicy FORWARD DROP',
|
|
'',
|
|
'deleteallchains',
|
|
''
|
|
);
|
|
|
|
for my $hosts ( @$criticalhosts ) {
|
|
my ( $interface, $host ) = ( split /:/, $hosts );
|
|
my $source = match_source_net $host;
|
|
my $dest = match_dest_net $host;
|
|
|
|
emit( "do_iptables -A INPUT -i $interface $source -j ACCEPT",
|
|
"do_iptables -A OUTPUT -o $interface $dest -j ACCEPT"
|
|
);
|
|
}
|
|
|
|
emit( '',
|
|
'for chain in INPUT OUTPUT; do',
|
|
' setpolicy $chain DROP',
|
|
"done\n"
|
|
);
|
|
} else {
|
|
emit( '',
|
|
'for chain in INPUT OUTPUT; do',
|
|
' setpolicy $chain ACCEPT',
|
|
'done',
|
|
'',
|
|
'setpolicy FORWARD DROP',
|
|
'',
|
|
"deleteallchains\n"
|
|
);
|
|
|
|
for my $hosts ( @$criticalhosts ) {
|
|
my ( $interface, $host ) = ( split /:/, $hosts );
|
|
my $source = match_source_net $host;
|
|
my $dest = match_dest_net $host;
|
|
|
|
emit( "do_iptables -A INPUT -i $interface $source -j ACCEPT",
|
|
"do_iptables -A OUTPUT -o $interface $dest -j ACCEPT"
|
|
);
|
|
}
|
|
|
|
emit( "\nsetpolicy INPUT DROP",
|
|
'',
|
|
'for chain in INPUT FORWARD; do',
|
|
' setcontinue $chain',
|
|
"done\n"
|
|
);
|
|
}
|
|
} elsif ( $config{ADMINISABSENTMINDED} ) {
|
|
emit( 'for chain in INPUT FORWARD; do',
|
|
' setpolicy $chain DROP',
|
|
'done',
|
|
'',
|
|
'setpolicy OUTPUT ACCEPT',
|
|
'',
|
|
'deleteallchains',
|
|
'',
|
|
'for chain in INPUT FORWARD; do',
|
|
' setcontinue $chain',
|
|
"done\n",
|
|
);
|
|
} else {
|
|
emit( 'for chain in INPUT OUTPUT FORWARD; do',
|
|
' setpolicy $chain DROP',
|
|
'done',
|
|
'',
|
|
"deleteallchains\n"
|
|
);
|
|
}
|
|
|
|
if ( $family == F_IPV6 ) {
|
|
emit <<'EOF';
|
|
#
|
|
# Enable link local and multi-cast
|
|
#
|
|
run_iptables -A INPUT -s ff80::/10 -j ACCEPT
|
|
run_iptables -A INPUT -d ff80::/10 -j ACCEPT
|
|
run_iptables -A INPUT -d ff00::/10 -j ACCEPT
|
|
EOF
|
|
|
|
emit <<'EOF' unless $config{ADMINISABSENTMINDED};
|
|
run_iptables -A OUTPUT -d ff80::/10 -j ACCEPT
|
|
run_iptables -A OUTPUT -d ff00::/10 -j ACCEPT
|
|
|
|
EOF
|
|
}
|
|
|
|
process_routestopped;
|
|
|
|
emit( 'do_iptables -A INPUT -i lo -j ACCEPT',
|
|
'do_iptables -A OUTPUT -o lo -j ACCEPT'
|
|
);
|
|
|
|
emit 'do_iptables -A OUTPUT -o lo -j ACCEPT' unless $config{ADMINISABSENTMINDED};
|
|
|
|
my $interfaces = find_interfaces_by_option 'dhcp';
|
|
|
|
if ( @$interfaces ) {
|
|
my $ports = $family == F_IPV4 ? '67:68' : '546:547';
|
|
|
|
for my $interface ( @$interfaces ) {
|
|
emit "do_iptables -A INPUT -p udp -i $interface --dport $ports -j ACCEPT";
|
|
emit "do_iptables -A OUTPUT -p udp -o $interface --dport $ports -j ACCEPT" unless $config{ADMINISABSENTMINDED};
|
|
#
|
|
# This might be a bridge
|
|
#
|
|
emit "do_iptables -A FORWARD -p udp -i $interface -o $interface --dport $ports -j ACCEPT";
|
|
}
|
|
}
|
|
|
|
emit '';
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
if ( $config{IP_FORWARDING} eq 'on' ) {
|
|
emit( 'echo 1 > /proc/sys/net/ipv4/ip_forward',
|
|
'progress_message2 IPv4 Forwarding Enabled' );
|
|
} elsif ( $config{IP_FORWARDING} eq 'off' ) {
|
|
emit( 'echo 0 > /proc/sys/net/ipv4/ip_forward',
|
|
'progress_message2 IPv4 Forwarding Disabled!'
|
|
);
|
|
}
|
|
} else {
|
|
for my $interface ( all_bridges ) {
|
|
emit "do_iptables -A FORWARD -p 58 -i $interface -o $interface -j ACCEPT";
|
|
}
|
|
|
|
if ( $config{IP_FORWARDING} eq 'on' ) {
|
|
emit( 'echo 1 > /proc/sys/net/ipv6/conf/all/forwarding',
|
|
'progress_message2 IPv6 Forwarding Enabled' );
|
|
} elsif ( $config{IP_FORWARDING} eq 'off' ) {
|
|
emit( 'echo 0 > /proc/sys/net/ipv6/conf/all/forwarding',
|
|
'progress_message2 IPv6 Forwarding Disabled!'
|
|
);
|
|
}
|
|
}
|
|
|
|
emit 'run_stopped_exit';
|
|
|
|
pop_indent;
|
|
|
|
emit '
|
|
set_state "Stopped"
|
|
|
|
logger -p kern.info "$PRODUCT Stopped"
|
|
|
|
case $COMMAND in
|
|
stop|clear)
|
|
;;
|
|
*)
|
|
#
|
|
# The firewall is being stopped when we were trying to do something
|
|
# else. Kill the shell in case we\'re running in a subshell
|
|
#
|
|
kill $$
|
|
;;
|
|
esac
|
|
}
|
|
';
|
|
|
|
}
|
|
|
|
#
|
|
# Second Phase of Script Generation
|
|
#
|
|
# copies the 'prog.functions' file into the script, generates
|
|
# clear_routing_and_traffic_shaping() and the first part of
|
|
# 'setup_routing_and_traffic_shaping()'
|
|
#
|
|
# The bulk of that function is produced by the various config file
|
|
# parsing routines that are called directly out of 'compiler()'.
|
|
#
|
|
# We create two separate functions rather than one so that the
|
|
# define_firewall() shell function can set global IP configuration variables
|
|
# after the old config has been cleared and before we start instantiating
|
|
# the new config. That way, the variables reflect the way that the
|
|
# distribution's tools have configured IP without any Shorewall
|
|
# modifications and the firewall configuration is the same after
|
|
# 'restart' as it is after 'start'.
|
|
#
|
|
# Note: This function is not called when $command eq 'check'. So it must have no side effects other
|
|
# than those related to writing to the object file.
|
|
#
|
|
sub generate_script_2 () {
|
|
|
|
unless ( $test ) {
|
|
if ( $family == F_IPV4 ) {
|
|
copy $globals{SHAREDIRPL} . 'prog.functions';
|
|
} else {
|
|
copy $globals{SHAREDIRPL} . 'prog.functions6';
|
|
}
|
|
}
|
|
|
|
emit( '',
|
|
'#',
|
|
'# Clear Routing and Traffic Shaping',
|
|
'#',
|
|
'clear_routing_and_traffic_shaping() {'
|
|
);
|
|
|
|
push_indent;
|
|
|
|
save_progress_message 'Initializing...';
|
|
|
|
if ( $export ) {
|
|
my $fn = find_file 'modules';
|
|
|
|
if ( $fn ne "$globals{SHAREDIR}/modules" && -f $fn ) {
|
|
emit 'echo MODULESDIR="$MODULESDIR" > ${VARDIR}/.modulesdir';
|
|
emit 'cat > ${VARDIR}/.modules << EOF';
|
|
open_file $fn;
|
|
while ( read_a_line ) {
|
|
emit_unindented $currentline;
|
|
}
|
|
emit_unindented 'EOF';
|
|
emit 'reload_kernel_modules < ${VARDIR}/.modules';
|
|
} else {
|
|
emit 'load_kernel_modules Yes';
|
|
}
|
|
} else {
|
|
emit 'load_kernel_modules Yes';
|
|
}
|
|
|
|
emit '';
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
for my $interface ( @{find_interfaces_by_option 'norfc1918'} ) {
|
|
emit ( "addr=\$(ip -f inet addr show $interface 2> /dev/null | grep 'inet\ ' | head -n1)",
|
|
'if [ -n "$addr" ]; then',
|
|
' addr=$(echo $addr | sed \'s/inet //;s/\/.*//;s/ peer.*//\')',
|
|
' for network in 10.0.0.0/8 176.16.0.0/12 192.168.0.0/16; do',
|
|
' if in_network $addr $network; then',
|
|
" error_message \"WARNING: The 'norfc1918' option has been specified on an interface with an RFC 1918 address. Interface:$interface\"",
|
|
' fi',
|
|
' done',
|
|
"fi\n" );
|
|
}
|
|
|
|
emit ( '[ "$COMMAND" = refresh ] && run_refresh_exit || run_init_exit',
|
|
'',
|
|
'qt1 $IPTABLES -L shorewall -n && qt1 $IPTABLES -F shorewall && qt1 $IPTABLES -X shorewall',
|
|
'',
|
|
'delete_proxyarp',
|
|
''
|
|
);
|
|
|
|
if ( $capabilities{NAT_ENABLED} ) {
|
|
emit( 'if [ -f ${VARDIR}/nat ]; then',
|
|
' while read external interface; do',
|
|
' del_ip_addr $external $interface',
|
|
' done < ${VARDIR}/nat',
|
|
'',
|
|
' rm -f ${VARDIR}/nat',
|
|
"fi\n" );
|
|
}
|
|
|
|
emit "delete_tc1\n" if $config{CLEAR_TC};
|
|
emit "disable_ipv6\n" if $config{DISABLE_IPV6};
|
|
|
|
} else {
|
|
emit ( '[ "$COMMAND" = refresh ] && run_refresh_exit || run_init_exit',
|
|
'',
|
|
'qt1 $IP6TABLES -L shorewall -n && qt1 $IP6TABLES -F shorewall && qt1 $IP6TABLES -X shorewall',
|
|
''
|
|
);
|
|
|
|
emit "delete_tc1\n" if $config{CLEAR_TC};
|
|
}
|
|
|
|
pop_indent;
|
|
|
|
emit "}\n";
|
|
|
|
emit( '#',
|
|
'# Setup Routing and Traffic Shaping',
|
|
'#',
|
|
'setup_routing_and_traffic_shaping() {'
|
|
);
|
|
|
|
push_indent;
|
|
|
|
}
|
|
|
|
#
|
|
# Third (final) stage of script generation.
|
|
#
|
|
# Generate the end of 'setup_routing_and_traffic_shaping()':
|
|
# Generate code for loading the various files in /var/lib/shorewall[-lite]
|
|
# Generate code to add IP addresses under ADD_IP_ALIASES and ADD_SNAT_ALIASES
|
|
#
|
|
# Generate the 'setup_netfilter()' function that runs iptables-restore.
|
|
# Generate the 'define_firewall()' function.
|
|
#
|
|
# Note: This function is not called when $command eq 'check'. So it must have no side effects other
|
|
# than those related to writing to the object file.
|
|
#
|
|
sub generate_script_3($) {
|
|
|
|
emit 'cat > ${VARDIR}/proxyarp << __EOF__';
|
|
dump_proxy_arp;
|
|
emit_unindented '__EOF__';
|
|
|
|
emit( '',
|
|
'if [ "$COMMAND" != refresh ]; then' );
|
|
|
|
push_indent;
|
|
|
|
emit 'cat > ${VARDIR}/zones << __EOF__';
|
|
dump_zone_contents;
|
|
emit_unindented '__EOF__';
|
|
|
|
pop_indent;
|
|
|
|
emit "fi\n";
|
|
|
|
emit '> ${VARDIR}/nat';
|
|
|
|
add_addresses;
|
|
|
|
pop_indent;
|
|
|
|
emit "}\n";
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
progress_message2 "Creating iptables-restore input...";
|
|
} else {
|
|
progress_message2 "Creating ip6tables-restore input...";
|
|
}
|
|
create_netfilter_load;
|
|
create_chainlist_reload( $_[0] );
|
|
|
|
emit "#\n# Start/Restart the Firewall\n#";
|
|
emit 'define_firewall() {';
|
|
push_indent;
|
|
|
|
emit "\nclear_routing_and_traffic_shaping";
|
|
|
|
set_global_variables;
|
|
|
|
emit '';
|
|
|
|
emit<<'EOF';
|
|
setup_routing_and_traffic_shaping
|
|
|
|
if [ $COMMAND = restore ]; then
|
|
iptables_save_file=${VARDIR}/$(basename $0)-iptables
|
|
if [ -f $iptables_save_file ]; then
|
|
cat $iptables_save_file | $IPTABLES_RESTORE # Use this nonsensical form to appease SELinux
|
|
else
|
|
fatal_error "$iptables_save_file does not exist"
|
|
fi
|
|
EOF
|
|
pop_indent;
|
|
setup_forwarding( $family );
|
|
push_indent;
|
|
emit<<'EOF';
|
|
set_state "Started"
|
|
else
|
|
if [ $COMMAND = refresh ]; then
|
|
chainlist_reload
|
|
EOF
|
|
setup_forwarding( $family );
|
|
emit<<'EOF';
|
|
run_refreshed_exit
|
|
do_iptables -N shorewall
|
|
set_state "Started"
|
|
else
|
|
setup_netfilter
|
|
restore_dynamic_rules
|
|
conditionally_flush_conntrack
|
|
EOF
|
|
setup_forwarding( $family );
|
|
emit<<'EOF';
|
|
run_start_exit
|
|
do_iptables -N shorewall
|
|
set_state "Started"
|
|
run_started_exit
|
|
fi
|
|
|
|
[ $0 = ${VARDIR}/.restore ] || cp -f $(my_pathname) ${VARDIR}/.restore
|
|
fi
|
|
|
|
date > ${VARDIR}/restarted
|
|
|
|
case $COMMAND in
|
|
start)
|
|
logger -p kern.info "$PRODUCT started"
|
|
;;
|
|
restart)
|
|
logger -p kern.info "$PRODUCT restarted"
|
|
;;
|
|
refresh)
|
|
logger -p kern.info "$PRODUCT refreshed"
|
|
;;
|
|
restore)
|
|
logger -p kern.info "$PRODUCT restored"
|
|
;;
|
|
esac
|
|
EOF
|
|
|
|
pop_indent;
|
|
|
|
emit "}\n";
|
|
|
|
unless ( $test ) {
|
|
if ( $family == F_IPV4 ) {
|
|
copy $globals{SHAREDIRPL} . 'prog.footer';
|
|
} else {
|
|
copy $globals{SHAREDIRPL} . 'prog.footer6';
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# The Compiler.
|
|
#
|
|
# Arguments are named -- see %parms below.
|
|
#
|
|
sub compiler {
|
|
|
|
my ( $objectfile, $directory, $verbosity, $timestamp , $debug, $chains , $log , $log_verbosity ) =
|
|
( '', '', -1, '', 0, '', '', -1 );
|
|
|
|
$export = 0;
|
|
$test = 0;
|
|
|
|
sub edit_boolean( $ ) {
|
|
my $val = numeric_value( shift );
|
|
defined($val) && ($val >= 0) && ($val < 2);
|
|
}
|
|
|
|
sub edit_verbosity( $ ) {
|
|
my $val = numeric_value( shift );
|
|
defined($val) && ($val >= MIN_VERBOSITY) && ($val <= MAX_VERBOSITY);
|
|
}
|
|
|
|
sub edit_family( $ ) {
|
|
my $val = numeric_value( shift );
|
|
defined($val) && ($val == F_IPV4 || $val == F_IPV6);
|
|
}
|
|
|
|
my %parms = ( object => { store => \$objectfile },
|
|
directory => { store => \$directory },
|
|
family => { store => \$family , edit => \&edit_family } ,
|
|
verbosity => { store => \$verbosity , edit => \&edit_verbosity } ,
|
|
timestamp => { store => \$timestamp, edit => \&edit_boolean } ,
|
|
debug => { store => \$debug, edit => \&edit_boolean } ,
|
|
export => { store => \$export , edit => \&edit_boolean } ,
|
|
chains => { store => \$chains },
|
|
log => { store => \$log },
|
|
log_verbosity => { store => \$log_verbosity, edit => \&edit_verbosity } ,
|
|
test => { store => \$test },
|
|
);
|
|
|
|
while ( defined ( my $name = shift ) ) {
|
|
fatal_error "Unknown parameter ($name)" unless my $ref = $parms{$name};
|
|
fatal_error "Undefined value supplied for parameter $name" unless defined ( my $val = shift ) ;
|
|
if ( $ref->{edit} ) {
|
|
fatal_error "Invalid value ( $val ) supplied for parameter $name" unless $ref->{edit}->($val);
|
|
}
|
|
|
|
${$ref->{store}} = $val;
|
|
}
|
|
|
|
reinitialize if $reused++ || $family == F_IPV6;
|
|
|
|
if ( $directory ne '' ) {
|
|
fatal_error "$directory is not an existing directory" unless -d $directory;
|
|
set_shorewall_dir( $directory );
|
|
}
|
|
|
|
set_verbose( $verbosity );
|
|
set_log($log, $log_verbosity) if $log;
|
|
set_timestamp( $timestamp );
|
|
set_debug( $debug );
|
|
#
|
|
# Get shorewall.conf and capabilities.
|
|
#
|
|
get_configuration( $export );
|
|
|
|
report_capabilities;
|
|
|
|
require_capability( 'MULTIPORT' , "Shorewall-perl $globals{VERSION}" , 's' );
|
|
require_capability( 'RECENT_MATCH' , 'MACLIST_TTL' , 's' ) if $config{MACLIST_TTL};
|
|
require_capability( 'XCONNMARK' , 'HIGH_ROUTE_MARKS=Yes' , 's' ) if $config{HIGH_ROUTE_MARKS};
|
|
require_capability( 'MANGLE_ENABLED' , 'Traffic Shaping' , 's' ) if $config{TC_ENABLED};
|
|
require_capability( 'CONNTRACK_MATCH' , 'RFC1918_STRICT=Yes' , 's' ) if $config{RFC1918_STRICT};
|
|
|
|
set_command( 'check', 'Checking', 'Checked' ) unless $objectfile;
|
|
|
|
initialize_chain_table;
|
|
|
|
unless ( $command eq 'check' ) {
|
|
create_temp_object( $objectfile );
|
|
generate_script_1;
|
|
}
|
|
|
|
#
|
|
# Allow user to load Perl modules
|
|
#
|
|
run_user_exit1 'compile';
|
|
#
|
|
# Process the zones file.
|
|
#
|
|
determine_zones;
|
|
#
|
|
# Process the interfaces file.
|
|
#
|
|
validate_interfaces_file ( $export );
|
|
#
|
|
# Process the hosts file.
|
|
#
|
|
validate_hosts_file;
|
|
#
|
|
# Report zone contents
|
|
#
|
|
zone_report;
|
|
#
|
|
# Do action pre-processing.
|
|
#
|
|
process_actions1;
|
|
#
|
|
# Process the Policy File.
|
|
#
|
|
validate_policy;
|
|
#
|
|
# Compile the 'stop_firewall()' function
|
|
#
|
|
compile_stop_firewall;
|
|
#
|
|
# Start Second Part of script
|
|
#
|
|
generate_script_2 unless $command eq 'check';
|
|
#
|
|
# Do all of the zone-independent stuff
|
|
#
|
|
add_common_rules;
|
|
#
|
|
# /proc stuff
|
|
#
|
|
if ( $family == F_IPV4 ) {
|
|
setup_arp_filtering;
|
|
setup_route_filtering;
|
|
setup_martian_logging;
|
|
}
|
|
|
|
setup_source_routing($family);
|
|
#
|
|
# Proxy Arp/Ndp
|
|
#
|
|
setup_proxy_arp;
|
|
#
|
|
# Handle MSS setings in the zones file
|
|
#
|
|
setup_zone_mss;
|
|
#
|
|
# [Re-]establish Routing
|
|
#
|
|
setup_providers;
|
|
#
|
|
# TOS
|
|
#
|
|
process_tos;
|
|
|
|
if ( $family == F_IPV4 ) {
|
|
#
|
|
# ECN
|
|
#
|
|
setup_ecn if $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED};
|
|
#
|
|
# Setup Masquerading/SNAT
|
|
#
|
|
setup_masq;
|
|
}
|
|
|
|
#
|
|
# MACLIST Filtration
|
|
#
|
|
setup_mac_lists 1;
|
|
#
|
|
# Process the rules file.
|
|
#
|
|
process_rules;
|
|
#
|
|
# Add Tunnel rules.
|
|
#
|
|
setup_tunnels;
|
|
#
|
|
# Post-rules action processing.
|
|
#
|
|
process_actions2;
|
|
process_actions3;
|
|
#
|
|
# MACLIST Filtration again
|
|
#
|
|
setup_mac_lists 2;
|
|
#
|
|
# Apply Policies
|
|
#
|
|
apply_policy_rules;
|
|
#
|
|
# TCRules and Traffic Shaping
|
|
#
|
|
setup_tc;
|
|
#
|
|
# Setup Nat
|
|
#
|
|
setup_nat;
|
|
#
|
|
# Setup NETMAP
|
|
#
|
|
setup_netmap;
|
|
#
|
|
# Accounting.
|
|
#
|
|
setup_accounting;
|
|
#
|
|
# We generate the matrix even though we don't write out the rules. That way, we insure that
|
|
# a compile of the script won't blow up during that step.
|
|
#
|
|
generate_matrix;
|
|
|
|
if ( $command eq 'check' ) {
|
|
if ( $family == F_IPV4 ) {
|
|
progress_message3 "Shorewall configuration verified";
|
|
} else {
|
|
progress_message3 "Shorewall6 configuration verified";
|
|
}
|
|
} else {
|
|
#
|
|
# Finish the script.
|
|
#
|
|
generate_script_3( $chains );
|
|
finalize_object ( $export );
|
|
#
|
|
# And generate the auxilary config file
|
|
#
|
|
generate_aux_config if $export;
|
|
}
|
|
|
|
close_log if $log;
|
|
|
|
1;
|
|
}
|
|
|
|
1;
|