2002-05-01 01:13:15 +02:00
#!/bin/sh
#
2005-08-31 17:27:22 +02:00
# The Shoreline Firewall (Shorewall) Packet Filtering Firewall - V3.0
2002-05-01 01:13:15 +02:00
#
2003-02-23 15:10:37 +01:00
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
2002-05-01 01:13:15 +02:00
#
2005-07-09 07:45:05 +02:00
# (c) 1999,2000,2001,2002,2003,2004,2005 - Tom Eastep (teastep@shorewall.net)
2005-10-06 00:51:29 +02:00
# tcstart from tc4shorewall Version 0.5
# (c) 2005 Arne Bernin <arne@ucbering.de>
# Modified by Tom Eastep for integration into the Shorewall distribution
# published under GPL Version 2#
2002-05-01 01:13:15 +02:00
#
# Complete documentation is available at http://shorewall.net
#
# This program is free software; you can redistribute it and/or modify
2003-02-23 15:10:37 +01:00
# it under the terms of Version 2 of the GNU General Public License
2002-05-01 01:13:15 +02:00
# 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
#
# If an error occurs while starting or restarting the firewall, the
# firewall is automatically stopped.
#
# Commands are:
#
2003-02-23 15:10:37 +01:00
# shorewall start Starts the firewall
2002-05-01 01:13:15 +02:00
# shorewall restart Restarts the firewall
# shorewall stop Stops the firewall
2005-07-09 07:45:05 +02:00
# shorewall reset Resets iptables packet and
2002-05-01 01:13:15 +02:00
# byte counts
2003-02-23 15:10:37 +01:00
# shorewall clear Remove all Shorewall chains
2002-05-01 01:13:15 +02:00
# and rules/policies.
# shorewall refresh . Rebuild the common chain
2003-03-10 01:47:12 +01:00
# shorewall check Verify the more heavily-used
# configuration files.
2002-10-23 18:48:40 +02:00
#
# Mutual exclusion -- These functions are jackets for the mutual exclusion
2003-01-07 00:01:23 +01:00
# routines in $FUNCTIONS. They invoke
2002-10-23 18:48:40 +02:00
# the corresponding function in that file if the user did
# not specify "nolock" on the runline.
#
2002-05-01 01:13:15 +02:00
my_mutex_on() {
2005-08-23 22:41:18 +02:00
[ -n "$nolock" ] || { mutex_on; HAVE_MUTEX=Yes; }
2002-05-01 01:13:15 +02:00
}
my_mutex_off() {
2005-08-23 23:35:56 +02:00
[ -n "$HAVE_MUTEX" ] && { mutex_off; HAVE_MUTEX=; }
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Message to stderr
#
2002-05-01 01:13:15 +02:00
error_message() # $* = Error Message
{
2002-05-30 14:55:47 +02:00
echo " $@" >&2
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Fatal error -- stops the firewall after issuing the error message
#
2002-05-01 01:13:15 +02:00
fatal_error() # $* = Error Message
{
2005-07-26 01:08:09 +02:00
echo " ERROR: $@" >&2
2005-07-09 06:45:32 +02:00
if [ $COMMAND = check ]; then
2003-04-21 17:12:59 +02:00
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
else
stop_firewall
fi
2002-05-01 01:13:15 +02:00
exit 2
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 07:45:05 +02:00
# Fatal error during startup -- generate an error message and abend without
2002-10-23 18:48:40 +02:00
# altering the state of the firewall
#
2002-05-01 01:13:15 +02:00
startup_error() # $* = Error Message
{
2005-07-26 01:08:09 +02:00
echo " ERROR: $@" >&2
2002-05-01 01:13:15 +02:00
my_mutex_off
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
2005-07-09 06:45:32 +02:00
[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE
2002-05-01 01:13:15 +02:00
kill $$
exit 2
}
2002-10-23 18:48:40 +02:00
#
# Send a message to STDOUT and the System Log
#
2002-05-03 00:56:27 +02:00
report () { # $* = message
echo "$@"
logger "$@"
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Write the passed args to $RESTOREBASE
2002-10-23 18:48:40 +02:00
#
2005-08-02 18:46:30 +02:00
save_command()
2002-05-01 01:13:15 +02:00
{
2005-07-09 06:45:32 +02:00
echo "$@" >> $RESTOREBASE
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Write a progress_message command to $RESTOREBASE
2002-10-23 18:48:40 +02:00
#
2005-08-02 18:46:30 +02:00
save_progress_message()
2002-05-01 01:13:15 +02:00
{
2005-07-09 06:45:32 +02:00
echo >> $RESTOREBASE
echo "progress_message \"$@\"" >> $RESTOREBASE
echo >> $RESTOREBASE
2002-05-01 01:13:15 +02:00
}
2002-12-05 01:18:47 +01:00
#
2005-07-09 06:45:32 +02:00
# Save the passed command in the restore script then run it -- returns the status of the command
# If the command involves file redirection then it must be enclosed in quotes as in:
2002-12-05 01:18:47 +01:00
#
2005-07-09 06:45:32 +02:00
# run_and_save_command "echo 1 > /proc/sys/net/ipv4/ip_forward"
#
2005-08-02 18:46:30 +02:00
run_and_save_command()
2005-07-09 06:45:32 +02:00
{
echo "$@" >> $RESTOREBASE
eval $*
}
2002-12-05 01:18:47 +01:00
2005-07-09 06:45:32 +02:00
#
# Run the passed command and if it succeeds, save it in the restore script. If it fails, stop the firewall and die
#
2005-08-02 18:46:30 +02:00
ensure_and_save_command()
2005-07-09 06:45:32 +02:00
{
if eval $* ; then
echo "$@" >> $RESTOREBASE
else
2005-09-08 22:57:29 +02:00
[ -z "$STOPPING" ] && { stop_firewall; exit 2; }
2005-07-09 06:45:32 +02:00
fi
}
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
#
2005-07-26 01:08:09 +02:00
# Append a file in /var/lib/shorewall to $RESTOREBASE
2005-07-09 06:45:32 +02:00
#
append_file() # $1 = File Name
{
2005-07-26 01:08:09 +02:00
save_command "cat > /var/lib/shorewall/$1 << __EOF__"
cat /var/lib/shorewall/$1 >> $RESTOREBASE
2005-07-09 06:45:32 +02:00
save_command __EOF__
2002-12-05 01:18:47 +01:00
}
2002-10-23 18:48:40 +02:00
#
# Run iptables and if an error occurs, stop the firewall and quit
#
2002-05-01 01:13:15 +02:00
run_iptables() {
2005-09-27 16:30:11 +02:00
#
# Purge the temporary files that we use to prevent duplicate '-m' specifications
#
2005-07-09 07:45:05 +02:00
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
if ! $IPTABLES $@ ; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:45:05 +02:00
error_message "ERROR: Command \"$IPTABLES $@\" Failed"
stop_firewall
exit 2
fi
2002-12-18 22:26:03 +01:00
fi
}
2002-12-18 22:58:21 +01:00
2002-12-18 22:26:03 +01:00
#
# Version of 'run_iptables' that inserts white space after "!" in the arg list
#
run_iptables2() {
2005-07-09 07:45:05 +02:00
case "$@" in
*!*)
run_iptables $(fix_bang $@)
;;
*)
run_iptables $@
;;
esac
2005-07-09 06:45:32 +02:00
}
#
# Quietly run iptables
#
qt_iptables() {
2005-09-27 16:30:11 +02:00
#
# Purge the temporary files that we use to prevent duplicate '-m' specifications
#
2005-07-09 06:45:32 +02:00
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
2005-07-09 07:45:05 +02:00
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
qt $IPTABLES $@
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Run ip and if an error occurs, stop the firewall and quit
#
2002-05-01 01:13:15 +02:00
run_ip() {
if ! ip $@ ; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:45:05 +02:00
error_message "ERROR: Command \"ip $@\" Failed"
stop_firewall
exit 2
fi
2002-05-01 01:13:15 +02:00
fi
}
2002-10-23 18:48:40 +02:00
#
# Run tc and if an error occurs, stop the firewall and quit
#
2002-05-01 01:13:15 +02:00
run_tc() {
if ! tc $@ ; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:45:05 +02:00
error_message "ERROR: Command \"tc $@\" Failed"
stop_firewall
exit 2
fi
2002-05-01 01:13:15 +02:00
fi
}
2005-07-09 07:55:29 +02:00
#
# Run ipset and if an error occurs, stop the firewall and quit
#
run_ipset() {
if ! ipset $@ ; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:55:29 +02:00
error_message "ERROR: Command \"ipset $@\" Failed"
stop_firewall
exit 2
fi
fi
}
2005-08-26 21:55:05 +02:00
#
# Add the implicit ACCEPT rules at the end of a rules file section
#
finish_chain_section() # $1 = canonical chain $2 = state list
{
2005-08-27 00:23:56 +02:00
local policy policychain
2005-08-26 21:55:05 +02:00
[ -n "$FASTACCEPT" ] || run_iptables -A $1 -m state --state $2 -j ACCEPT
2005-09-17 05:49:24 +02:00
2005-08-26 21:55:05 +02:00
if list_search RELATED $(separate_list $2) ; then
2005-08-27 00:23:56 +02:00
if is_policy_chain $1 ; then
if eval test -n \"\$${1}_synparams\" ; then
if [ $SECTION = DONE ]; then
eval policy=\$${1}_policy
case $policy in
ACCEPT|CONTINUE|QUEUE)
run_iptables -A $1 -p tcp --syn -j @$1
;;
*)
2005-09-19 16:43:22 +02:00
2005-08-27 00:23:56 +02:00
esac
else
run_iptables -A $1 -p tcp --syn -j @$1
fi
fi
else
eval policychain=\$${1}_policychain
2005-09-17 05:49:24 +02:00
2005-08-27 00:23:56 +02:00
if eval test -n \"\$${policychain}_synparams\" ; then
run_iptables -A $1 -p tcp --syn -j @$policychain
fi
fi
fi
2005-08-26 21:55:05 +02:00
}
finish_section() # $1 = Section(s)
{
local zone zone1 chain
if [ "$COMMAND" != check ]; then
for zone in $ZONES $FW; do
for zone1 in $ZONES $FW; do
chain=${zone}2${zone1}
if havechain $chain; then
finish_chain_section $chain $1
fi
done
done
fi
}
2002-10-23 18:48:40 +02:00
#
# Create a filter chain
#
# If the chain isn't one of the common chains then add a rule to the chain
# allowing packets that are part of an established connection. Create a
2003-10-30 16:42:45 +01:00
# variable exists_${1} and set its value to Yes to indicate that the chain now
2002-10-23 18:48:40 +02:00
# exists.
#
2005-10-01 17:55:41 +02:00
createchain() # $1 = chain name, $2 = If "yes", do section-end processing
2002-05-01 01:13:15 +02:00
{
2005-07-09 06:45:32 +02:00
local c=$(chain_base $1)
2003-10-25 02:54:01 +02:00
2002-05-01 01:13:15 +02:00
run_iptables -N $1
2003-02-08 21:58:44 +01:00
if [ $2 = yes ]; then
2005-08-26 21:55:05 +02:00
case $SECTION in
2005-08-27 00:23:56 +02:00
NEW|DONE)
2005-08-26 21:55:05 +02:00
finish_chain_section $1 ESTABLISHED,RELATED
;;
RELATED)
finish_chain_section $1 ESTABLISHED
;;
esac
2002-05-01 01:13:15 +02:00
fi
2003-10-30 16:42:45 +01:00
eval exists_${c}=Yes
2002-05-01 01:13:15 +02:00
}
2003-08-10 18:01:21 +02:00
createchain2() # $1 = chain name, $2 = If "yes", create default rules
{
2005-07-09 06:45:32 +02:00
local c=$(chain_base $1)
2003-10-25 02:54:01 +02:00
2005-07-09 07:45:05 +02:00
if $IPTABLES -N $1; then
2003-08-10 18:01:21 +02:00
if [ $2 = yes ]; then
2005-08-26 21:55:05 +02:00
case $SECTION in
2005-08-27 00:23:56 +02:00
NEW|DONE)
2005-08-26 21:55:05 +02:00
finish_chain_section $1 ESTABLISHED,RELATED
;;
RELATED)
finish_chain_section $1 ESTABLISHED
;;
esac
2005-09-17 05:49:24 +02:00
2003-08-10 18:01:21 +02:00
fi
2005-09-19 16:43:22 +02:00
2003-10-30 16:42:45 +01:00
eval exists_${c}=Yes
2003-08-10 18:01:21 +02:00
fi
2005-08-26 21:55:05 +02:00
2003-08-10 18:01:21 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Determine if a chain exists
#
2005-07-09 07:55:29 +02:00
# When we create a chain "x", we create a variable named exists_x and
2003-10-30 16:42:45 +01:00
# set its value to Yes. This function tests for the "exists_" variable
2002-10-23 18:48:40 +02:00
# corresponding to the passed chain having the value of "Yes".
#
2002-05-01 01:13:15 +02:00
havechain() # $1 = name of chain
{
2005-07-09 06:45:32 +02:00
local c=$(chain_base $1)
2003-10-25 02:54:01 +02:00
2003-10-30 16:42:45 +01:00
eval test \"\$exists_${c}\" = Yes
2002-05-01 01:13:15 +02:00
}
2002-12-04 22:17:14 +01:00
#
# Query NetFilter about the existence of a filter chain
#
chain_exists() # $1 = chain name
{
2005-07-09 07:45:05 +02:00
qt $IPTABLES -L $1 -n
2002-12-04 22:17:14 +01:00
}
2003-02-23 15:10:37 +01:00
2002-12-04 22:17:14 +01:00
#
# Query NetFilter about the existence of a mangle chain
#
mangle_chain_exists() # $1 = chain name
{
2005-07-09 07:45:05 +02:00
qt $IPTABLES -t mangle -L $1 -n
2002-12-04 22:17:14 +01:00
}
2003-02-23 15:10:37 +01:00
2002-10-23 18:48:40 +02:00
#
# Ensure that a chain exists (create it if it doesn't)
#
2002-05-01 01:13:15 +02:00
ensurechain() # $1 = chain name
{
2003-02-08 21:58:44 +01:00
havechain $1 || createchain $1 yes
2002-05-01 01:13:15 +02:00
}
2005-07-09 06:45:32 +02:00
ensurechain1() # $1 = chain name
{
havechain $1 || createchain $1 no
}
2002-10-23 18:48:40 +02:00
#
# Add a rule to a chain creating the chain if necessary
#
2002-05-01 01:13:15 +02:00
addrule() # $1 = chain name, remainder of arguments specify the rule
2005-07-09 07:45:05 +02:00
{
ensurechain $1
run_iptables -A $@
}
addrule2() # $1 = chain name, remainder of arguments specify the rule
2002-05-01 01:13:15 +02:00
{
ensurechain $1
2005-07-09 06:45:32 +02:00
run_iptables2 -A $@
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Create a nat chain
#
2003-10-30 16:42:45 +01:00
# Create a variable exists_nat_${1} and set its value to Yes to indicate that
2002-10-23 18:48:40 +02:00
# the chain now exists.
#
2002-05-18 15:45:23 +02:00
createnatchain() # $1 = chain name
{
run_iptables -t nat -N $1
2003-10-30 16:42:45 +01:00
eval exists_nat_${1}=Yes
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Determine if a nat chain exists
#
2003-10-30 16:42:45 +01:00
# When we create a chain "chain", we create a variable named exists_nat_chain
# and set its value to Yes. This function tests for the "exists_" variable
2002-10-23 18:48:40 +02:00
# corresponding to the passed chain having the value of "Yes".
#
2002-05-18 15:45:23 +02:00
havenatchain() # $1 = name of chain
{
2003-10-30 16:42:45 +01:00
eval test \"\$exists_nat_${1}\" = Yes
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
2003-02-20 00:52:03 +01:00
# Ensure that a nat chain exists (create it if it doesn't)
2002-10-23 18:48:40 +02:00
#
2002-05-18 15:45:23 +02:00
ensurenatchain() # $1 = chain name
{
havenatchain $1 || createnatchain $1
}
2002-10-23 18:48:40 +02:00
#
# Add a rule to a nat chain creating the chain if necessary
#
2002-05-18 15:45:23 +02:00
addnatrule() # $1 = chain name, remainder of arguments specify the rule
{
ensurenatchain $1
2002-12-18 22:26:03 +01:00
run_iptables2 -t nat -A $@
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Delete a chain if it exists
#
2002-05-01 01:13:15 +02:00
deletechain() # $1 = name of chain
{
2005-07-09 07:45:05 +02:00
qt $IPTABLES -L $1 -n && qt $IPTABLES -F $1 && qt $IPTABLES -X $1
2002-05-01 01:13:15 +02:00
}
2002-11-13 01:57:48 +01:00
#
# Determine if a chain is a policy chain
#
is_policy_chain() # $1 = name of chain
{
eval test \"\$${1}_is_policy\" = Yes
2003-02-23 15:10:37 +01:00
}
2002-11-13 01:57:48 +01:00
2002-10-23 18:48:40 +02:00
#
# Set a standard chain's policy
#
2002-05-01 01:13:15 +02:00
setpolicy() # $1 = name of chain, $2 = policy
{
run_iptables -P $1 $2
}
2002-10-23 18:48:40 +02:00
#
2003-06-11 03:01:48 +02:00
# Set a standard chain to enable established and related connections
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
setcontinue() # $1 = name of chain
{
2003-06-11 03:01:48 +02:00
run_iptables -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Flush one of the NAT table chains
#
2002-05-01 01:13:15 +02:00
flushnat() # $1 = name of chain
{
run_iptables -t nat -F $1
}
2003-02-24 16:24:55 +01:00
#
# Flush one of the Mangle table chains
#
flushmangle() # $1 = name of chain
{
run_iptables -t mangle -F $1
}
2005-07-26 01:08:09 +02:00
#
2005-09-02 22:46:53 +02:00
# This function assumes that the TMP_DIR variable is set and that
# its value named an existing directory.
2005-07-26 01:08:09 +02:00
#
2005-09-02 22:46:53 +02:00
determine_zones()
2005-07-26 01:08:09 +02:00
{
2005-09-03 02:48:37 +02:00
local zone parent parents rest new_zone_file= r
2005-09-02 22:46:53 +02:00
merge_zone()
{
local z zones="$ZONES" merged=
2005-09-03 02:48:37 +02:00
if [ -n "$parents" ]; then
ZONES=
for z in $zones; do
if [ -z "$merged" ] && list_search $z $parents; then
ZONES="$ZONES $zone"
merged=Yes
fi
ZONES="$ZONES $z"
done
else
ZONES="$ZONES $zone"
fi
2005-09-03 00:56:35 +02:00
}
2005-09-02 22:46:53 +02:00
strip_file zones
ZONES=
2005-10-04 16:54:56 +02:00
IPV4_ZONES=
IPSEC_ZONES=
2005-09-02 22:46:53 +02:00
2005-10-03 19:59:19 +02:00
[ "$IPSECFILE" = zones ] && new_zone_file=Yes || test -n "${FW:=fw}"
2005-09-02 22:46:53 +02:00
while read zone type rest; do
expandv zone type
case $zone in
*:*)
parents=${zone#*:}
zone=${zone%:*}
[ -n "$zone" ] || startup_error "Invalid nested zone syntax: :$parents"
parents=$(separate_list $parents)
;;
*)
parents=
;;
esac
for parent in $parents; do
2005-09-19 16:43:22 +02:00
[ "$parent" = "$FW" ] && startup_error "Sub-zones of the firewall zone are not allowed"
2005-09-02 22:46:53 +02:00
list_search $parent $ZONES || startup_error "Parent zone not defined: $parent"
2005-09-19 16:43:22 +02:00
done
2005-07-26 01:08:09 +02:00
[ ${#zone} -gt 5 ] && startup_error "Zone name longer than 5 characters: $zone"
case "$zone" in
[0-9*])
startup_error "Illegal zone name \"$zone\" in zones file"
;;
2005-09-02 22:46:53 +02:00
all|none)
startup_error "Reserved zone name \"$zone\" in zones file"
2005-07-26 01:08:09 +02:00
;;
esac
2005-09-02 22:46:53 +02:00
if [ -n "$new_zone_file" ]; then
2005-09-30 19:16:22 +02:00
case ${type:=ipv4} in
2005-09-30 20:22:57 +02:00
ipv4|IPv4|IPV4|plain|-)
2005-09-02 22:46:53 +02:00
list_search $zone $ZONES $FW && startup_error "Zone $zone is defined more than once"
merge_zone
2005-10-04 16:54:56 +02:00
IPV4_ZONES="$IPV4_ZONES $zone"
2005-09-02 22:46:53 +02:00
;;
2005-09-30 20:22:57 +02:00
ipsec|IPSEC|ipsec4|IPSEC4)
2005-09-02 22:46:53 +02:00
list_search $zone $ZONES $FW && startup_error "Zone $zone is defined more than once"
[ -n "$POLICY_MATCH" ] || fatal_error "Your kernel and/or iptables does not support policy match"
eval ${zone}_is_ipsec=Yes
eval ${zone}_is_complex=Yes
merge_zone
2005-10-04 16:54:56 +02:00
IPSEC_ZONES="$IPSEC_ZONES $zone"
2005-09-02 22:46:53 +02:00
;;
firewall)
2005-10-03 19:39:36 +02:00
[ -n "$FW" ] && startup_error "Only one firewall zone may be defined"
2005-09-02 22:46:53 +02:00
list_search $zone $ZONES && startup_error "Zone $zone is defined more than once"
[ -n "$parents" ] && startup_error "The firewall zone may not be nested"
2005-09-03 02:48:37 +02:00
for r in $rest; do
[ "x$r" = x- ] || startup_error "OPTIONS not allowed on the firewall zone"
done
2005-09-02 22:46:53 +02:00
FW=$zone
;;
*)
2005-09-03 02:48:37 +02:00
startup_error "Invalid Zone Type: $type"
2005-09-02 22:46:53 +02:00
;;
esac
2005-10-04 16:54:56 +02:00
eval ${zone}_type=$type
2005-09-02 22:46:53 +02:00
else
2005-09-03 02:48:37 +02:00
list_search $zone $ZONES $FW && startup_error "Zone $zone is defined more than once"
2005-09-02 22:46:53 +02:00
ZONES="$ZONES $zone"
2005-10-04 16:54:56 +02:00
IPV4_ZONES="$IPV4_ZONES $zone"
eval ${zone}_type=ipv4
2005-09-02 22:46:53 +02:00
fi
done < $TMP_DIR/zones
2005-07-26 01:08:09 +02:00
2005-09-30 21:20:27 +02:00
[ -z "$ZONES" ] && startup_error "No ipv4 or ipsec Zones Defined"
2005-07-26 01:08:09 +02:00
2005-09-02 22:46:53 +02:00
[ -z "$FW" ] && startup_error "No Firewall Zone Defined"
2005-07-26 01:08:09 +02:00
}
2002-10-23 18:48:40 +02:00
#
2002-12-07 04:21:32 +01:00
# Find interfaces to a given zone
2002-10-23 18:48:40 +02:00
#
2002-12-07 04:21:32 +01:00
# Search the variables representing the contents of the interfaces file and
2003-02-23 15:10:37 +01:00
# for each record matching the passed ZONE, echo the expanded contents of
2002-12-07 04:21:32 +01:00
# the "INTERFACE" column
#
find_interfaces() # $1 = interface zone
2002-05-18 15:45:23 +02:00
{
2002-12-07 04:21:32 +01:00
local zne=$1
local z
local interface
2002-05-18 15:45:23 +02:00
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
eval z=\$$(chain_base $interface)_zone
2002-12-07 04:21:32 +01:00
[ "x${z}" = x${zne} ] && echo $interface
done
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Forward Chain for an interface
#
2002-05-18 15:45:23 +02:00
forward_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_fwd
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Input Chain for an interface
#
2002-05-18 15:45:23 +02:00
input_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_in
2002-05-18 15:45:23 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Output Chain for an interface
#
2002-07-05 17:56:02 +02:00
output_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_out
2002-07-05 17:56:02 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Masquerade Chain for an interface
#
2002-07-05 23:57:37 +02:00
masq_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_masq
2002-07-05 23:57:37 +02:00
}
2002-10-23 18:48:40 +02:00
#
# MAC Verification Chain for an interface
#
2002-10-23 17:58:53 +02:00
mac_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_mac
}
2005-07-26 01:08:09 +02:00
macrecent_target() # $1 - interface
{
[ -n "$MACLIST_TTL" ] && echo $(chain_base $1)_rec || echo RETURN
}
2005-07-09 06:45:32 +02:00
#
# Functions for creating dynamic zone rules
#
dynamic_fwd() # $1 = interface
{
echo $(chain_base $1)_dynf
}
dynamic_in() # $1 = interface
{
echo $(chain_base $1)_dyni
}
dynamic_out() # $1 = interface
{
echo $(chain_base $1)_dyno
}
dynamic_chains() #$1 = interface
{
local c=$(chain_base $1)
echo ${c}_dyni ${c}_dynf ${c}_dyno
2002-10-23 17:58:53 +02:00
}
2002-10-23 18:48:40 +02:00
#
# DNAT Chain from a zone
#
2002-07-05 23:57:37 +02:00
dnat_chain() # $1 = zone
{
echo ${1}_dnat
}
2002-10-23 18:48:40 +02:00
#
2005-08-02 23:06:05 +02:00
# SNAT Chain to an interface
2002-10-23 18:48:40 +02:00
#
2005-08-02 23:06:05 +02:00
snat_chain() # $1 = interface
2002-07-05 23:57:37 +02:00
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_snat
2003-02-24 16:24:55 +01:00
}
#
# ECN Chain to an interface
#
ecn_chain() # $1 = interface
{
2005-07-09 06:45:32 +02:00
echo $(chain_base $1)_ecn
2002-07-05 23:57:37 +02:00
}
2002-10-23 18:48:40 +02:00
#
# First chains for an interface
#
2002-05-18 15:45:23 +02:00
first_chains() #$1 = interface
{
2005-07-09 06:45:32 +02:00
local c=$(chain_base $1)
2002-05-18 15:45:23 +02:00
echo ${c}_fwd ${c}_in
}
2003-08-21 15:18:51 +02:00
#
2005-07-09 07:45:05 +02:00
# Horrible hack to work around an iptables limitation
#
2005-08-02 18:46:30 +02:00
iprange_echo()
2005-07-09 07:45:05 +02:00
{
if [ -f $TMP_DIR/iprange ]; then
echo $@
else
echo "-m iprange $@"
> $TMP_DIR/iprange
fi
}
2005-07-09 07:55:29 +02:00
#
# Get set flags (ipsets).
#
get_set_flags() # $1 = set name and optional [levels], $2 = src or dst
{
local temp setname=$1 options=$2
[ -n "$IPSET_MATCH" ] || fatal_error "Your kernel and/or iptables does not include ipset match: $1"
case $1 in
*\[[1-6]\])
temp=${1#*\[}
temp=${temp%\]}
setname=${1%\[*}
while [ $temp -gt 1 ]; do
options="$options,$2"
temp=$(($temp - 1))
2005-09-19 16:43:22 +02:00
done
2005-07-09 07:55:29 +02:00
;;
*\[*\])
options=${1#*\[}
options=${options%\]}
setname=${1%\[*}
;;
*)
;;
esac
2005-08-02 18:46:30 +02:00
2005-07-09 07:55:29 +02:00
echo "--set ${setname#+} $options"
2005-08-02 18:46:30 +02:00
}
2005-07-09 07:45:05 +02:00
#
# Source IP range
#
source_ip_range() # $1 = Address or Address Range
{
case $1 in
*.*.*.*-*.*.*.*)
case $1 in
!*)
iprange_echo "! --src-range ${1#!}"
;;
*)
iprange_echo "--src-range $1"
;;
esac
;;
2005-07-09 07:55:29 +02:00
!+*)
echo "-m set ! $(get_set_flags ${1#!} src)"
;;
+*)
echo "-m set $(get_set_flags $1 src)"
;;
2005-07-09 07:45:05 +02:00
*)
echo "-s $1"
;;
esac
}
#
# Destination IP range
#
dest_ip_range() # $1 = Address or Address Range
{
case $1 in
*.*.*.*-*.*.*.*)
case $1 in
!*)
iprange_echo "! --dst-range ${1#!}"
;;
*)
iprange_echo "--dst-range $1"
;;
esac
;;
2005-07-09 07:55:29 +02:00
!+*)
echo "-m set ! $(get_set_flags ${1#!} dst)"
;;
+*)
echo "-m set $(get_set_flags $1 dst)"
;;
2005-07-09 07:45:05 +02:00
*)
echo "-d $1"
;;
esac
}
both_ip_ranges() # $1 = Source address or range, $2 = dest address or range
{
2005-07-09 07:55:29 +02:00
local rangeprefix= setprefix= rangematch= setmatch=
2005-07-09 07:45:05 +02:00
2005-08-02 18:46:30 +02:00
case $1 in
2005-07-09 07:45:05 +02:00
*.*.*.*-*.*.*.*)
2005-07-09 07:55:29 +02:00
rangeprefix="-m iprange"
rangematch="--src-range $1"
;;
!+*)
setprefix="-m set"
setmatch="! $(get_set_flags ${1#!} src)"
;;
+*)
setprefix="-m set"
setmatch="$(get_set_flags $1 src)"
2005-07-09 07:45:05 +02:00
;;
*)
2005-07-09 07:55:29 +02:00
rangematch="-s $1"
2005-07-09 07:45:05 +02:00
;;
esac
2005-08-02 18:46:30 +02:00
case $2 in
2005-07-09 07:45:05 +02:00
*.*.*.*-*.*.*.*)
2005-07-09 07:55:29 +02:00
rangeprefix="-m iprange"
rangematch="$rangematch --dst-range $2"
;;
!+*)
setprefix="-m set"
match="$setmatch ! $(get_set_flags ${2#!} dst)"
;;
+*)
setprefix="-m set"
setmatch="$setmatch $(get_set_flags $2 dst)"
2005-07-09 07:45:05 +02:00
;;
*)
2005-07-09 07:55:29 +02:00
rangematch="$rangematch -d $2"
2005-07-09 07:45:05 +02:00
;;
esac
2005-07-09 07:55:29 +02:00
echo "$rangeprefix $rangematch $setprefix $setmatch"
2005-08-02 18:46:30 +02:00
}
2005-07-09 07:45:05 +02:00
#
# Horrible hack to work around an iptables limitation
2003-08-21 15:18:51 +02:00
#
2005-08-02 18:46:30 +02:00
physdev_echo()
2003-08-21 15:18:51 +02:00
{
2005-07-09 06:45:32 +02:00
if [ -f $TMP_DIR/physdev ]; then
echo $@
else
echo -m physdev $@
> $TMP_DIR/physdev
fi
2003-08-21 15:18:51 +02:00
}
#
2005-07-09 06:45:32 +02:00
# We allow hosts to be specified by IP address or by physdev. These two functions
# are used to produce the proper match in a netfilter rule.
2003-08-21 15:18:51 +02:00
#
2005-07-09 06:45:32 +02:00
match_source_hosts()
{
if [ -n "$BRIDGING" ]; then
case $1 in
*:*)
2005-07-09 07:45:05 +02:00
physdev_echo "--physdev-in ${1%:*} $(source_ip_range ${1#*:})"
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:55:29 +02:00
*.*.*.*|+*|!+*)
2005-07-09 07:45:05 +02:00
echo $(source_ip_range $1)
2005-07-09 06:45:32 +02:00
;;
*)
physdev_echo "--physdev-in $1"
;;
esac
else
2005-07-09 07:45:05 +02:00
echo $(source_ip_range $1)
2005-07-09 06:45:32 +02:00
fi
}
match_dest_hosts()
2003-08-21 15:18:51 +02:00
{
2005-07-09 06:45:32 +02:00
if [ -n "$BRIDGING" ]; then
case $1 in
*:*)
2005-07-09 07:45:05 +02:00
physdev_echo "--physdev-out ${1%:*} $(dest_ip_range ${1#*:})"
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:55:29 +02:00
*.*.*.*|+*|!+*)
2005-07-09 07:45:05 +02:00
echo $(dest_ip_range $1)
2005-07-09 06:45:32 +02:00
;;
*)
physdev_echo "--physdev-out $1"
;;
esac
else
2005-07-09 07:45:05 +02:00
echo $(dest_ip_range $1)
2005-07-09 06:45:32 +02:00
fi
2003-08-21 15:18:51 +02:00
}
2005-07-09 06:45:32 +02:00
#
2005-08-02 18:46:30 +02:00
# Similarly, the source or destination in a rule can be qualified by a device name. If
2005-07-09 06:45:32 +02:00
# the device is defined in /etc/shorewall/interfaces then a normal interface match is
# generated (-i or -o); otherwise, a physdev match is generated.
#-------------------------------------------------------------------------------------
2003-08-21 15:18:51 +02:00
#
2005-07-09 06:45:32 +02:00
# loosely match the passed interface with those in /etc/shorewall/interfaces.
2003-08-21 15:18:51 +02:00
#
2005-07-09 06:45:32 +02:00
known_interface() # $1 = interface name
{
local iface
2005-07-09 07:45:05 +02:00
for iface in $ALL_INTERFACES ; do
2005-07-09 06:45:32 +02:00
if if_match $iface $1 ; then
return 0
fi
done
return 1
}
match_source_dev()
{
if [ -n "$BRIDGING" ]; then
list_search $1 $all_ports && physdev_echo "--physdev-in $1" || echo -i $1
else
echo -i $1
fi
}
match_dest_dev()
{
if [ -n "$BRIDGING" ]; then
list_search $1 $all_ports && physdev_echo "--physdev-out $1" || echo -o $1
else
echo -o $1
fi
}
verify_interface()
2003-08-21 15:18:51 +02:00
{
2005-07-09 07:45:05 +02:00
known_interface $1 || { [ -n "$BRIDGING" ] && list_search $1 $all_ports ; }
}
#
# Determine if communication to/from a host is encrypted using IPSEC
#
is_ipsec_host() # $1 = zone, $2 = host
{
eval local is_ipsec=\$${1}_is_ipsec
eval local hosts=\"\$${1}_ipsec_hosts\"
test -n "$is_ipsec" || list_search $2 $hosts
}
#
# Generate a match for decrypted packets
#
match_ipsec_in() # $1 = zone, $2 = host
{
if is_ipsec_host $1 $2 ; then
eval local options=\"\$${1}_ipsec_options \$${1}_ipsec_in_options\"
echo "-m policy --pol ipsec --dir in $options"
elif [ -n "$POLICY_MATCH" ]; then
echo "-m policy --pol none --dir in"
fi
}
#
# Generate a match for packets that will be encrypted
#
match_ipsec_out() # $1 = zone, $2 = host
{
if is_ipsec_host $1 $2 ; then
eval local options=\"\$${1}_ipsec_options \$${1}_ipsec_out_options\"
echo "-m policy --pol ipsec --dir out $options"
elif [ -n "$POLICY_MATCH" ]; then
echo "-m policy --pol none --dir out"
fi
}
#
# Jacket for ip_range() that takes care of iprange match
#
firewall_ip_range() # $1 = IP address or range
{
[ -n "$IPRANGE_MATCH" ] && echo $1 || ip_range $1
2003-08-21 15:18:51 +02:00
}
2005-07-09 06:45:32 +02:00
#
2002-10-23 18:48:40 +02:00
#
# Find hosts in a given zone
#
# Read hosts file and for each record matching the passed ZONE,
# echo the expanded contents of the "HOST(S)" column
#
2002-05-01 01:13:15 +02:00
find_hosts() # $1 = host zone
{
2003-07-06 17:31:26 +02:00
local hosts interface address addresses
2002-05-01 01:13:15 +02:00
while read z hosts options; do
2005-07-09 06:45:32 +02:00
if [ "x$(expand $z)" = "x$1" ]; then
2003-07-06 17:31:26 +02:00
expandv hosts
2005-07-09 06:45:32 +02:00
interface=${hosts%%:*}
2003-07-06 17:31:26 +02:00
addresses=${hosts#*:}
2005-08-02 18:46:30 +02:00
for address in $(separate_list $addresses); do
2003-07-06 17:31:26 +02:00
echo $interface:$address
done
fi
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/hosts
}
2002-10-23 18:48:40 +02:00
#
# Determine the interfaces on the firewall
#
# For each zone, create a variable called ${zone}_interfaces. This
# variable contains a space-separated list of interfaces to the zone
#
2002-05-01 01:13:15 +02:00
determine_interfaces() {
2005-07-26 01:08:09 +02:00
for zone in $ZONES; do
2005-07-09 06:45:32 +02:00
interfaces=$(find_interfaces $zone)
interfaces=$(echo $interfaces) # Remove extra trash
2003-02-20 00:52:03 +01:00
eval ${zone}_interfaces=\"\$interfaces\"
2002-05-01 01:13:15 +02:00
done
}
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
#
# Determine if an interface has a given option
#
interface_has_option() # $1 = interface, #2 = option
{
local options
eval options=\$$(chain_base $1)_options
list_search $2 $options
}
2002-10-23 18:48:40 +02:00
#
# Determine the defined hosts in each zone and generate report
#
2002-05-01 01:13:15 +02:00
determine_hosts() {
2005-07-26 01:08:09 +02:00
for zone in $ZONES; do
2005-07-09 06:45:32 +02:00
hosts=$(find_hosts $zone)
hosts=$(echo $hosts) # Remove extra trash
2003-02-08 21:58:44 +01:00
2002-07-06 00:24:40 +02:00
eval interfaces=\$${zone}_interfaces
2002-05-01 01:13:15 +02:00
for interface in $interfaces; do
2005-07-09 06:45:32 +02:00
if interface_has_option $interface detectnets; then
networks=$(get_routed_networks $interface)
2002-05-01 01:13:15 +02:00
else
2005-07-09 06:45:32 +02:00
networks=0.0.0.0/0
2002-05-01 01:13:15 +02:00
fi
2004-01-24 00:48:30 +01:00
2005-07-09 07:55:29 +02:00
for network in $networks; do
2004-01-24 00:48:30 +01:00
if [ -z "$hosts" ]; then
2005-07-09 07:55:29 +02:00
hosts=$interface:$network
2004-01-24 00:48:30 +01:00
else
2005-07-09 07:55:29 +02:00
hosts="$hosts $interface:$network"
2005-07-09 06:45:32 +02:00
fi
if interface_has_option $interface routeback; then
2005-07-09 07:55:29 +02:00
eval ${zone}_routeback=\"$interface:$network \$${zone}_routeback\"
2004-01-24 00:48:30 +01:00
fi
done
2002-05-01 01:13:15 +02:00
done
2002-07-09 17:44:49 +02:00
interfaces=
2003-02-23 15:10:37 +01:00
2002-07-09 17:44:49 +02:00
for host in $hosts; do
interface=${host%:*}
2005-07-09 06:45:32 +02:00
if list_search $interface $interfaces; then
list_search $interface:0.0.0.0/0 $hosts && \
startup_error "Invalid zone definition for zone $zone"
list_search $interface:0/0 $hosts && \
startup_error "Invalid zone definition for zone $zone"
eval ${zone}_is_complex=Yes
else
2002-07-09 17:44:49 +02:00
if [ -z "$interfaces" ]; then
interfaces=$interface
else
interfaces="$interfaces $interface"
fi
fi
done
eval ${zone}_interfaces="\$interfaces"
2002-05-01 01:13:15 +02:00
eval ${zone}_hosts="\$hosts"
if [ -n "$hosts" ]; then
2005-07-26 01:08:09 +02:00
display_list "$zone Zone:" $hosts
2002-05-18 21:04:45 +02:00
else
2005-07-26 01:08:09 +02:00
error_message "WARNING: Zone $zone is empty"
2003-02-23 15:10:37 +01:00
fi
2002-05-01 01:13:15 +02:00
done
}
2002-10-23 18:48:40 +02:00
#
# Ensure that the passed zone is defined in the zones file or is the firewall
#
2002-05-01 01:13:15 +02:00
validate_zone() # $1 = zone
{
2005-07-26 01:08:09 +02:00
list_search $1 $ZONES $FW
2002-05-01 01:13:15 +02:00
}
2005-07-09 06:45:32 +02:00
#
# Ensure that the passed zone is defined in the zones file.
#
validate_zone1() # $1 = zone
{
2005-07-26 01:08:09 +02:00
list_search $1 $ZONES
2005-07-09 06:45:32 +02:00
}
2002-05-01 01:13:15 +02:00
2002-10-23 18:48:40 +02:00
#
# Validate the zone names and options in the interfaces file
#
2002-05-01 01:13:15 +02:00
validate_interfaces_file() {
2004-01-24 00:48:30 +01:00
local wildcard
2005-07-09 06:45:32 +02:00
local found_obsolete_option=
local z interface networks options r iface option
2004-01-24 00:48:30 +01:00
2005-07-09 08:13:05 +02:00
while read z interface networks options; do
2005-07-09 06:45:32 +02:00
expandv z interface networks options
r="$z $interface $networks $options"
2002-12-07 04:21:32 +01:00
[ "x$z" = "x-" ] && z=
2003-02-23 15:10:37 +01:00
if [ -n "$z" ]; then
2002-12-07 04:21:32 +01:00
validate_zone $z || startup_error "Invalid zone ($z) in record \"$r\""
fi
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
list_search $interface $ALL_INTERFACES && \
2003-02-08 21:58:44 +01:00
startup_error "Duplicate Interface $interface"
2004-01-24 00:48:30 +01:00
wildcard=
2003-02-08 21:58:44 +01:00
case $interface in
2005-07-09 06:45:32 +02:00
*:*|+)
2003-02-08 21:58:44 +01:00
startup_error "Invalid Interface Name: $interface"
;;
2005-07-09 06:45:32 +02:00
*+)
2004-01-24 00:48:30 +01:00
wildcard=Yes
;;
2003-02-08 21:58:44 +01:00
esac
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
ALL_INTERFACES="$ALL_INTERFACES $interface"
2005-07-09 06:45:32 +02:00
options=$(separate_list $options)
iface=$(chain_base $interface)
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
eval ${iface}_broadcast="$networks"
2003-11-08 03:38:30 +01:00
eval ${iface}_zone="$z"
eval ${iface}_options=\"$options\"
2002-05-18 15:45:23 +02:00
2002-12-19 22:30:58 +01:00
for option in $options; do
2002-05-01 01:13:15 +02:00
case $option in
2005-07-09 07:55:29 +02:00
-)
;;
2005-10-01 17:55:41 +02:00
dhcp|tcpflags|arp_filter|routefilter|logmartians|sourceroute|blacklist|proxyarp|maclist|nosmurfs|upnp|-)
2005-08-14 18:45:48 +02:00
;;
norfc1918)
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
startup_error "The 'norfc1918' option may not be specified on an interface with an RFC 1918 address. Interface:$interface"
fi
done
fi
2005-07-26 01:08:09 +02:00
;;
arp_ignore=*)
eval ${iface}_arp_ignore=${option#*=}
;;
arp_ignore)
eval ${iface}_arp_ignore=1
2003-01-21 01:34:00 +01:00
;;
2004-01-24 00:48:30 +01:00
detectnets)
[ -n "$wildcard" ] && \
startup_error "The \"detectnets\" option may not be used with a wild-card interface"
;;
2003-04-01 04:00:37 +02:00
routeback)
[ -n "$z" ] || startup_error "The routeback option may not be specified on a multi-zone interface"
;;
2003-01-21 01:34:00 +01:00
*)
2005-07-26 01:08:09 +02:00
error_message "WARNING: Invalid option ($option) in record \"$r\""
2003-01-27 03:54:43 +01:00
;;
2002-05-01 01:13:15 +02:00
esac
done
done < $TMP_DIR/interfaces
2005-08-02 18:46:30 +02:00
2005-07-09 07:55:29 +02:00
[ -z "$ALL_INTERFACES" ] && startup_error "No Interfaces Defined"
}
#
# Check that a mark value or mask is less that 256
#
verify_mark() # $1 = value to test
{
2005-08-02 18:46:30 +02:00
verify_mark1()
2005-07-09 07:55:29 +02:00
{
[ $1 -lt 256 ]
}
2005-08-02 18:46:30 +02:00
2005-07-09 07:55:29 +02:00
verify_mark2()
{
verify_mark1 $1 2> /dev/null
}
2005-08-02 18:46:30 +02:00
2005-07-09 07:55:29 +02:00
verify_mark2 $1 || fatal_error "Invalid Mark or Mask value: $1"
2002-05-01 01:13:15 +02:00
}
2005-07-09 07:55:29 +02:00
#
2005-08-02 18:46:30 +02:00
# Process the providers file
2005-07-09 07:55:29 +02:00
#
setup_providers()
{
2005-07-28 00:41:52 +02:00
local table number mark duplicate interface gateway options provider address copy route loose addresses rulenum pref echobin=$(mywhich echo)
2005-07-19 00:40:26 +02:00
copy_table() {
run_ip route show table $duplicate | while read net route; do
case $net in
default|nexthop)
;;
*)
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route add table $number $net $route"
2005-07-19 00:40:26 +02:00
;;
esac
done
}
2005-08-02 18:46:30 +02:00
copy_and_edit_table() {
2005-07-19 00:40:26 +02:00
run_ip route show table $duplicate | while read net route; do
case $net in
default|nexthop)
;;
*)
if list_search $(find_device $route) $copy; then
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route add table $number $net $route"
2005-07-19 00:40:26 +02:00
fi
;;
esac
done
}
2005-07-09 07:55:29 +02:00
add_a_provider() {
local t n iface option
2005-10-06 18:35:20 +02:00
[ -n "$MANGLE_ENABLED" ] || fatal_error "Providers require mangle support in your kernel and iptables"
2005-07-09 07:55:29 +02:00
for t in $PROVIDERS; do
if [ "$t" = "$table" ]; then
fatal_error "Duplicate Provider: $table, provider: \"$provider\""
fi
eval n=\$${t}_number
if [ $n -eq $number ]; then
fatal_error "Duplicate Provider number: $number, provider: \"$provider\""
fi
done
eval ${table}_number=$number
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
2005-09-15 01:01:13 +02:00
run_and_save_command "[ -n \"\$NOROUTES\" ] || qt ip route flush table $number"
2005-07-09 07:55:29 +02:00
2005-08-30 22:29:42 +02:00
if [ "x${duplicate:=-}" != x- ]; then
if [ "x${copy:=-}" != "x-" ]; then
copy="$interface $(separate_list $copy)"
copy_and_edit_table
else
copy_table
fi
2005-07-19 00:40:26 +02:00
fi
2005-07-09 07:55:29 +02:00
fi
if [ "x$gateway" = xdetect ] ; then
#
# First assume that this is some sort of point-to-point interface
#
gateway=$( find_peer $(ip addr ls $interface ) )
#
# Maybe there's a default route through this gateway already
#
[ -n "$gateway" ] || gateway=$(find_gateway $(ip route ls dev $interface))
#
# Last hope -- is there a load-balancing route through the interface?
#
[ -n "$gateway" ] || gateway=$(find_nexthop $interface)
#
# Be sure we found one
#
[ -n "$gateway" ] || fatal_error "Unable to detect the gateway through interface $interface"
fi
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route replace $gateway dev $interface table $number"
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route add default via $gateway dev $interface table $number"
2005-08-30 22:29:42 +02:00
fi
2005-09-27 16:30:11 +02:00
if [ x${mark} != x- ]; then
verify_mark $mark
2005-07-09 07:55:29 +02:00
2005-09-27 16:30:11 +02:00
eval ${table}_mark=$mark
2005-07-09 07:55:29 +02:00
2005-09-27 16:30:11 +02:00
if [ $COMMAND != check ]; then
run_and_save_command "[ -n \"\$NOROUTES\" ] || qt ip rule del fwmark $mark"
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip rule add fwmark $mark pref $((10000 + $mark)) table $number"
fi
2005-08-30 22:29:42 +02:00
fi
2005-07-09 07:55:29 +02:00
2005-07-19 00:40:26 +02:00
loose=
2005-07-09 07:55:29 +02:00
for option in $(separate_list $options); do
case $option in
-)
;;
track)
2005-07-10 01:23:45 +02:00
list_search $interface $ROUTEMARK_INTERFACES && \
fatal_error "Interface $interface is tracked through an earlier provider"
2005-07-09 07:55:29 +02:00
iface=$(chain_base $interface)
2005-09-27 16:30:11 +02:00
[ x${mark} = x- ] && fatal_error "The 'track' option requires a numeric value in the MARK column - Provider \"$provider\""
2005-07-09 07:55:29 +02:00
eval ${iface}_routemark=$mark
ROUTEMARK_INTERFACES="$ROUTEMARK_INTERFACES $interface"
;;
balance=*)
DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight ${option#*=}"
;;
balance)
DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight 1"
;;
2005-07-26 01:08:09 +02:00
loose)
loose=Yes
;;
2005-07-09 07:55:29 +02:00
*)
2005-07-26 01:08:09 +02:00
error_message " WARNING: Invalid option ($option) ignored in provider \"$provider\""
2005-07-09 07:55:29 +02:00
;;
esac
done
2005-07-21 21:48:33 +02:00
rulenum=0
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
find_interface_addresses $interface | while read address; do
2005-09-15 01:01:13 +02:00
run_and_save_command "[ -n \"\$NOROUTES\" ] || qt ip rule del from $address"
2005-08-30 22:29:42 +02:00
if [ -z "$loose" ]; then
2005-09-27 16:30:11 +02:00
pref=$((20000 + $rulenum * 1000 + $number ))
2005-08-30 22:29:42 +02:00
rulenum=$(($rulenum + 1))
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip rule add from $address pref $pref table $number"
2005-08-30 22:29:42 +02:00
fi
done
fi
2005-07-09 07:55:29 +02:00
}
2005-09-19 16:43:22 +02:00
2005-07-09 07:55:29 +02:00
strip_file providers $1
if [ -s $TMP_DIR/providers ]; then
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
echo "Processing $1..."
2005-07-09 07:55:29 +02:00
2005-08-30 22:29:42 +02:00
save_progress_message "Restoring Providers..."
else
echo "Validating $1..."
fi
2005-09-19 16:43:22 +02:00
2005-07-19 00:40:26 +02:00
while read table number mark duplicate interface gateway options copy; do
expandv table number mark duplicate interface gateway options copy
provider="$table $number $mark $duplicate $interface $gateway $options $copy"
2005-07-09 07:55:29 +02:00
add_a_provider
PROVIDERS="$PROVIDERS $table"
progress_message " Provider $provider Added"
done < $TMP_DIR/providers
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
if [ -n "$PROVIDERS" ]; then
if [ -n "$DEFAULT_ROUTE" ]; then
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route replace default scope global $DEFAULT_ROUTE"
2005-08-30 22:29:42 +02:00
progress_message " Default route $DEFAULT_ROUTE Added."
fi
2005-07-09 07:55:29 +02:00
2005-08-30 22:29:42 +02:00
cat > /etc/iproute2/rt_tables <<EOF
2005-07-09 07:55:29 +02:00
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
EOF
2005-08-30 22:29:42 +02:00
for table in $PROVIDERS; do
eval number=\$${table}_number
${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables
done
2005-07-09 07:55:29 +02:00
2005-08-30 22:29:42 +02:00
save_command "cat > /etc/iproute2/rt_tables << __EOF__"
cat /etc/iproute2/rt_tables >> $RESTOREBASE
save_command __EOF__
2005-07-09 07:55:29 +02:00
2005-09-19 16:43:22 +02:00
fi
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route flush cache"
2005-08-30 22:29:42 +02:00
fi
2005-07-09 07:55:29 +02:00
fi
}
2005-08-02 18:46:30 +02:00
2002-10-23 18:48:40 +02:00
#
# Validate the zone names and options in the hosts file
#
2002-05-01 01:13:15 +02:00
validate_hosts_file() {
2005-07-09 06:45:32 +02:00
local z hosts options r interface host option port ports
2005-08-02 18:46:30 +02:00
check_bridge_port()
2005-07-09 06:45:32 +02:00
{
list_search $1 $ports || ports="$ports $1"
list_search ${interface}:${1} $zports || zports="$zports ${interface}:${1}"
list_search $1 $all_ports || all_ports="$all_ports $1"
}
2005-07-09 07:45:05 +02:00
while read z hosts options; do
expandv z hosts options
r="$z $hosts $options"
validate_zone1 $z || startup_error "Invalid zone ($z) in record \"$r\""
2002-06-29 01:42:00 +02:00
2005-07-09 07:45:05 +02:00
case $hosts in
*:*)
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
interface=${hosts%%:*}
iface=$(chain_base $interface)
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
list_search $interface $ALL_INTERFACES || \
startup_error "Unknown interface ($interface) in record \"$r\""
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
hosts=${hosts#*:}
;;
*)
2005-10-03 19:39:36 +02:00
startup_error "Invalid HOST(S) column contents: $hosts"
2005-07-09 07:45:05 +02:00
;;
esac
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
eval ports=\$${iface}_ports
eval zports=\$${z}_ports
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
for host in $(separate_list $hosts); do
if [ -n "$BRIDGING" ]; then
case $host in
*:*)
known_interface ${host%:*} && \
startup_error "Bridged interfaces may not be defined in /etc/shorewall/interfaces: $host"
check_bridge_port ${host%%:*}
;;
*.*.*.*)
;;
2005-07-09 07:55:29 +02:00
+*)
2005-09-19 16:43:22 +02:00
eval ${z}_is_complex=Yes
2005-07-09 07:55:29 +02:00
;;
2005-07-09 07:45:05 +02:00
*)
known_interface $host && \
startup_error "Bridged interfaces may not be defined in /etc/shorewall/interfaces: $host"
check_bridge_port $host
;;
esac
2005-07-09 07:55:29 +02:00
else
case $host in
+*)
2005-09-19 16:43:22 +02:00
eval ${z}_is_complex=Yes
2005-07-09 07:55:29 +02:00
;;
esac
2005-07-09 07:45:05 +02:00
fi
for option in $(separate_list $options) ; do
case $option in
2005-10-01 17:55:41 +02:00
maclist|norfc1918|blacklist|tcpflags|nosmurfs|-)
2005-07-09 07:45:05 +02:00
;;
ipsec)
[ -n "$POLICY_MATCH" ] || \
startup_error "Your kernel and/or iptables does not support policy match: ipsec"
eval ${z}_ipsec_hosts=\"\$${z}_ipsec_hosts $interface:$host\"
eval ${z}_is_complex=Yes
;;
routeback)
[ -z "$ports" ] && \
eval ${z}_routeback=\"$interface:$host \$${z}_routeback\"
;;
*)
2005-07-26 01:08:09 +02:00
error_message "WARNING: Invalid option ($option) in record \"$r\""
2005-07-09 07:45:05 +02:00
;;
esac
done
done
if [ -n "$ports" ]; then
eval ${iface}_ports=\"$ports\"
eval ${z}_ports=\"$zports\"
fi
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
done < $TMP_DIR/hosts
[ -n "$all_ports" ] && echo " Bridge ports are: $all_ports"
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Format a match by the passed MAC address
# The passed address begins with "~" and uses "-" as a separator between bytes
# Example: ~01-02-03-04-05-06
#
2002-05-01 01:13:15 +02:00
mac_match() # $1 = MAC address formated as described above
{
2005-07-09 06:45:32 +02:00
echo "--match mac --mac-source $(echo $1 | sed 's/~//;s/-/:/g')"
2003-02-23 15:10:37 +01:00
}
2002-05-01 01:13:15 +02:00
2002-10-23 18:48:40 +02:00
#
# validate the policy file
#
2002-05-01 01:13:15 +02:00
validate_policy()
{
2002-12-07 04:21:32 +01:00
local clientwild
local serverwild
local zone
local zone1
local pc
local chain
2002-12-31 02:10:28 +01:00
local policy
local loglevel
local synparams
2003-02-27 23:28:06 +01:00
print_policy() # $1 = source zone, $2 = destination zone
{
2005-07-09 06:45:32 +02:00
[ $COMMAND != check ] || \
2003-10-26 17:22:01 +01:00
[ $1 = $2 ] || \
2003-02-27 23:28:06 +01:00
[ $1 = all ] || \
[ $2 = all ] || \
2005-07-09 06:45:32 +02:00
progress_message " Policy for $1 to $2 is $policy using chain $chain"
2003-02-27 23:28:06 +01:00
}
2005-08-17 23:54:57 +02:00
ALL_POLICY_CHAINS=
2002-12-07 04:21:32 +01:00
2005-08-18 22:18:08 +02:00
for zone in $ZONES $FW; do
chain=${zone}2${zone}
eval ${chain}_is_policy=Yes
eval ${chain}_is_optional=Yes
eval ${chain}_policy=ACCEPT
2005-08-27 00:23:56 +02:00
eval ${chain}_policychain=$chain
2005-08-18 22:18:08 +02:00
ALL_POLICY_CHAINS="$ALL_POLICY_CHAINS $chain"
2005-09-19 16:43:22 +02:00
done
2005-08-18 22:18:08 +02:00
2003-02-08 21:58:44 +01:00
strip_file policy
2002-05-01 01:13:15 +02:00
while read client server policy loglevel synparams; do
2002-07-06 00:24:40 +02:00
expandv client server policy loglevel synparams
2002-12-07 04:21:32 +01:00
clientwild=
serverwild=
2002-05-01 01:13:15 +02:00
case "$client" in
all|ALL)
2002-12-07 04:21:32 +01:00
clientwild=Yes
2002-05-01 01:13:15 +02:00
;;
*)
if ! validate_zone $client; then
2003-02-08 21:58:44 +01:00
startup_error "Undefined zone $client"
2002-07-06 00:24:40 +02:00
fi
2002-05-01 01:13:15 +02:00
esac
case "$server" in
all|ALL)
2002-12-07 04:21:32 +01:00
serverwild=Yes
2002-05-01 01:13:15 +02:00
;;
*)
if ! validate_zone $server; then
2003-02-08 21:58:44 +01:00
startup_error "Undefined zone $server"
2002-07-06 00:24:40 +02:00
fi
2002-05-01 01:13:15 +02:00
esac
case $policy in
2005-07-09 07:45:05 +02:00
ACCEPT|REJECT|DROP|CONTINUE|QUEUE)
2003-11-08 03:38:30 +01:00
;;
NONE)
[ "$client" = "$FW" -o "$server" = "$FW" ] && \
startup_error " $client $server $policy $loglevel $synparams: NONE policy not allowed to/from the $FW zone"
[ -n "$clientwild" -o -n "$serverwild" ] && \
startup_error " $client $server $policy $loglevel $synparams: NONE policy not allowed with \"all\""
2002-05-01 01:13:15 +02:00
;;
*)
2003-02-08 21:58:44 +01:00
startup_error "Invalid policy $policy"
2002-05-01 01:13:15 +02:00
;;
2002-07-06 00:24:40 +02:00
esac
2002-05-01 01:13:15 +02:00
2002-11-13 01:57:48 +01:00
chain=${client}2${server}
if is_policy_chain $chain ; then
2005-08-18 23:39:30 +02:00
if eval test \$${chain}_is_optional = Yes ; then
eval ${chain}_is_optional=
else
startup_error "Duplicate policy: $client $server $policy"
fi
2002-11-13 01:57:48 +01:00
fi
2005-08-27 00:23:56 +02:00
[ "x$loglevel" = "x-" ] && loglevel=
[ "x$synparams" = "x-" ] && synparams=
2002-12-07 04:21:32 +01:00
2005-08-17 23:54:57 +02:00
[ $policy = NONE ] || ALL_POLICY_CHAINS="$ALL_POLICY_CHAINS $chain"
2002-12-07 04:21:32 +01:00
eval ${chain}_is_policy=Yes
eval ${chain}_policy=$policy
eval ${chain}_loglevel=$loglevel
eval ${chain}_synparams=$synparams
if [ -n "${clientwild}" ]; then
if [ -n "${serverwild}" ]; then
2005-07-26 01:08:09 +02:00
for zone in $ZONES $FW all; do
for zone1 in $ZONES $FW all; do
2002-12-07 04:21:32 +01:00
eval pc=\$${zone}2${zone1}_policychain
2002-12-31 02:10:28 +01:00
if [ -z "$pc" ]; then
2002-12-07 04:21:32 +01:00
eval ${zone}2${zone1}_policychain=$chain
2003-03-21 05:14:20 +01:00
eval ${zone}2${zone1}_policy=$policy
2003-02-27 23:28:06 +01:00
print_policy $zone $zone1
2002-12-31 02:10:28 +01:00
fi
2002-12-07 04:21:32 +01:00
done
done
else
2005-07-26 01:08:09 +02:00
for zone in $ZONES $FW all; do
2002-12-07 04:21:32 +01:00
eval pc=\$${zone}2${server}_policychain
2003-02-23 15:10:37 +01:00
2002-12-31 02:10:28 +01:00
if [ -z "$pc" ]; then
2002-12-07 04:21:32 +01:00
eval ${zone}2${server}_policychain=$chain
2003-03-21 05:14:20 +01:00
eval ${zone}2${server}_policy=$policy
2003-02-27 23:28:06 +01:00
print_policy $zone $server
2002-12-31 02:10:28 +01:00
fi
2002-12-07 04:21:32 +01:00
done
fi
elif [ -n "$serverwild" ]; then
2005-07-26 01:08:09 +02:00
for zone in $ZONES $FW all; do
2002-12-07 04:21:32 +01:00
eval pc=\$${client}2${zone}_policychain
2003-02-23 15:10:37 +01:00
2002-12-31 02:10:28 +01:00
if [ -z "$pc" ]; then
2003-02-23 15:10:37 +01:00
eval ${client}2${zone}_policychain=$chain
2003-03-21 05:14:20 +01:00
eval ${client}2${zone}_policy=$policy
2003-02-27 23:28:06 +01:00
print_policy $client $zone
2002-12-31 02:10:28 +01:00
fi
2002-12-07 04:21:32 +01:00
done
else
eval ${chain}_policychain=${chain}
2003-02-27 23:28:06 +01:00
print_policy $client $server
2003-02-23 15:10:37 +01:00
fi
2002-11-13 01:57:48 +01:00
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/policy
}
2002-10-23 18:48:40 +02:00
#
# Find broadcast addresses
#
2002-05-18 21:04:45 +02:00
find_broadcasts() {
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
eval bcast=\$$(chain_base $interface)_broadcast
2002-05-18 21:04:45 +02:00
if [ "x$bcast" = "xdetect" ]; then
2005-07-09 06:45:32 +02:00
ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u
2002-05-18 21:04:45 +02:00
elif [ "x${bcast}" != "x-" ]; then
2005-07-09 06:45:32 +02:00
echo $(separate_list $bcast)
2002-05-01 01:13:15 +02:00
fi
2002-12-07 04:21:32 +01:00
done
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Find interface address--returns the first IP address assigned to the passed
# device
#
2005-07-09 07:45:05 +02:00
find_first_interface_address() # $1 = interface
2002-07-09 17:44:49 +02:00
{
2003-02-23 15:10:37 +01:00
#
2002-07-09 17:44:49 +02:00
# get the line of output containing the first IP address
#
2005-07-09 06:45:32 +02:00
addr=$(ip -f inet addr show $1 2> /dev/null | grep inet | head -n1)
2002-07-09 17:44:49 +02:00
#
# If there wasn't one, bail out now
#
[ -n "$addr" ] || fatal_error "Can't determine the IP address of $1"
#
# Strip off the trailing VLSM mask (or the peer IP in case of a P-t-P link)
# along with everything else on the line
#
echo $addr | sed 's/inet //;s/\/.*//;s/ peer.*//'
}
2002-10-23 18:48:40 +02:00
#
# Find interfaces that have the passed option specified
#
2002-05-01 01:13:15 +02:00
find_interfaces_by_option() # $1 = option
{
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
eval options=\$$(chain_base $interface)_options
2002-12-07 04:21:32 +01:00
list_search $1 $options && echo $interface
done
2002-05-01 01:13:15 +02:00
}
2005-07-26 01:08:09 +02:00
#
# This slightly slower version is used to find both the option and option followed
# by equal sign ("=") and a value
#
find_interfaces_by_option1() # $1 = option
{
local options option
for interface in $ALL_INTERFACES; do
eval options=\$$(chain_base $interface)_options
for option in $options; do
if [ "${option%=*}" = "$1" ]; then
echo $interface
break
fi
done
done
}
2002-10-23 18:48:40 +02:00
#
# Find hosts with the passed option
#
2002-05-01 01:13:15 +02:00
find_hosts_by_option() # $1 = option
{
2005-07-09 07:45:05 +02:00
local ignore hosts interface address addresses options ipsec= list
2003-07-06 18:10:23 +02:00
2002-05-01 01:13:15 +02:00
while read ignore hosts options; do
expandv options
2005-07-09 07:45:05 +02:00
list=$(separate_list $options)
if list_search $1 $list; then
list_search ipsec $list && ipsec=ipsec || ipsec=none
2003-07-06 18:10:23 +02:00
expandv hosts
2005-07-09 06:45:32 +02:00
interface=${hosts%%:*}
2003-07-06 18:10:23 +02:00
addresses=${hosts#*:}
2005-08-02 18:46:30 +02:00
for address in $(separate_list $addresses); do
2005-07-09 07:45:05 +02:00
echo ${ipsec}^$interface:$address
2003-07-06 18:10:23 +02:00
done
fi
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/hosts
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
interface_has_option $interface $1 && \
2005-07-09 07:45:05 +02:00
echo none^${interface}:0.0.0.0/0
2002-12-07 04:21:32 +01:00
done
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Flush and delete all user-defined chains in the filter table
#
2002-05-01 01:13:15 +02:00
deleteallchains() {
run_iptables -F
run_iptables -X
}
2005-07-09 07:55:29 +02:00
##
2002-10-23 18:48:40 +02:00
# Source a user exit file if it exists
#
2002-05-01 01:13:15 +02:00
run_user_exit() # $1 = file name
{
2005-07-09 06:45:32 +02:00
local user_exit=$(find_file $1)
2002-05-01 01:13:15 +02:00
if [ -f $user_exit ]; then
2005-07-09 06:45:32 +02:00
progress_message "Processing $user_exit ..."
2002-05-01 01:13:15 +02:00
. $user_exit
fi
}
2003-05-21 23:36:05 +02:00
#
# Add a logging rule.
#
2005-07-09 07:45:05 +02:00
log_rule_limit() # $1 = log level, $2 = chain, $3 = display Chain $4 = disposition , $5 = rate limit $6=log tag $7=command $... = predicates for the rule
2003-05-21 23:36:05 +02:00
{
local level=$1
local chain=$2
2005-07-09 07:45:05 +02:00
local displayChain=$3
local disposition=$4
2003-05-21 23:36:05 +02:00
local rulenum=
2005-07-09 07:45:05 +02:00
local limit="${5:-$LOGLIMIT}"
local tag=${6:+$6 }
local command=${7:--A}
2005-07-09 06:45:32 +02:00
local prefix
local base=$(chain_base $displayChain)
2003-05-21 23:36:05 +02:00
2005-07-09 07:45:05 +02:00
shift;shift;shift;shift;shift;shift;shift
if [ -n "$tag" -a -n "$LOGTAGONLY" ]; then
displayChain=$tag
tag=
fi
2003-05-21 23:36:05 +02:00
2003-05-27 19:42:12 +02:00
if [ -n "$LOGRULENUMBERS" ]; then
2005-07-09 06:45:32 +02:00
eval rulenum=\$${base}_logrules
2003-05-21 23:36:05 +02:00
2005-07-09 06:45:32 +02:00
rulenum=${rulenum:-1}
2003-05-21 23:36:05 +02:00
2005-07-09 07:45:05 +02:00
prefix="$(printf "$LOGFORMAT" $displayChain $rulenum $disposition)${tag}"
2003-05-21 23:36:05 +02:00
2003-05-27 19:42:12 +02:00
rulenum=$(($rulenum + 1))
2005-07-09 06:45:32 +02:00
eval ${base}_logrules=$rulenum
2003-05-27 19:42:12 +02:00
else
2005-07-09 07:45:05 +02:00
prefix="$(printf "$LOGFORMAT" $displayChain $disposition)${tag}"
2005-07-09 06:45:32 +02:00
fi
if [ ${#prefix} -gt 29 ]; then
2005-07-09 07:45:05 +02:00
prefix="$(echo $prefix | truncate 29)"
2005-07-26 01:08:09 +02:00
error_message "WARNING: Log Prefix shortened to \"$prefix\""
2005-07-09 06:45:32 +02:00
fi
case $level in
ULOG)
2005-07-09 07:45:05 +02:00
if ! $IPTABLES $command $chain $@ $limit -j ULOG $LOGPARMS --ulog-prefix "$prefix" ; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:45:05 +02:00
error_message "ERROR: Command \"$IPTABLES $command $chain $@ $limit -j ULOG $LOGPARMS --ulog-prefix \"$prefix\"\" Failed"
stop_firewall
exit 2
fi
fi
2005-07-09 06:45:32 +02:00
;;
*)
2005-07-09 07:45:05 +02:00
if ! $IPTABLES $command $chain $@ $limit -j LOG $LOGPARMS --log-level $level --log-prefix "$prefix"; then
2005-09-08 22:57:29 +02:00
if [ -z "$STOPPING" ]; then
2005-07-09 07:45:05 +02:00
error_message "ERROR: Command \"$IPTABLES $command $chain $@ $limit -j LOG $LOGPARMS --log-level $level --log-prefix \"$prefix\"\" Failed"
stop_firewall
exit 2
fi
fi
2005-07-09 06:45:32 +02:00
;;
esac
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
if [ $? -ne 0 ] ; then
2005-09-08 22:57:29 +02:00
[ -z "$STOPPING" ] && { stop_firewall; exit 2; }
2003-05-27 19:42:12 +02:00
fi
2003-05-21 23:36:05 +02:00
}
2003-08-22 17:27:08 +02:00
log_rule() # $1 = log level, $2 = chain, $3 = disposition , $... = predicates for the rule
{
local level=$1
local chain=$2
local disposition=$3
shift;shift;shift
2005-07-09 07:45:05 +02:00
log_rule_limit $level $chain $chain $disposition "$LOGLIMIT" "" -A $@
2003-08-22 17:27:08 +02:00
}
2003-11-27 19:24:57 +01:00
#
# Set /proc/sys/net/ipv4/ip_forward based on $IP_FORWARDING
#
setup_forwarding() {
2005-07-09 06:45:32 +02:00
save_progress_message "Restoring IP Forwarding..."
2003-11-27 19:24:57 +01:00
case "$IP_FORWARDING" in
[Oo][Nn])
2005-07-09 06:45:32 +02:00
run_and_save_command "echo 1 > /proc/sys/net/ipv4/ip_forward"
2003-11-27 19:24:57 +01:00
echo "IP Forwarding Enabled"
;;
[Oo][Ff][Ff])
2005-07-09 06:45:32 +02:00
run_and_save_command "echo 0 > /proc/sys/net/ipv4/ip_forward"
2003-11-27 19:24:57 +01:00
echo "IP Forwarding Disabled!"
;;
esac
}
2005-07-09 06:45:32 +02:00
#
# Disable IPV6
#
disable_ipv6() {
local foo="$(ip -f inet6 addr ls 2> /dev/null)"
if [ -n "$foo" ]; then
2005-07-27 22:30:16 +02:00
if qt mywhich ip6tables; then
2005-07-09 06:45:32 +02:00
save_progress_message "Disabling IPV6..."
ip6tables -P FORWARD DROP && save_command ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP && save_command ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP && save_command ip6tables -P OUTPUT DROP
else
error_message "WARNING: DISABLE_IPV6=Yes in shorewall.conf but this system does not appear to have ip6tables"
fi
fi
}
disable_ipv6_1() {
local foo="$(ip -f inet6 addr ls 2> /dev/null)"
if [ -n "$foo" ]; then
2005-07-27 22:30:16 +02:00
if qt mywhich ip6tables; then
2005-07-09 06:45:32 +02:00
progress_message "Disabling IPV6..."
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
else
error_message "WARNING: DISABLE_IPV6=Yes in shorewall.conf but this system does not appear to have ip6tables"
fi
fi
}
2005-07-09 07:45:05 +02:00
#
# Process the routestopped file either adding or deleting rules
#
process_routestopped() # $1 = command
{
2005-07-09 07:55:29 +02:00
local hosts= interface host host1 options networks source= dest= matched
2005-07-09 07:45:05 +02:00
while read interface host options; do
expandv interface host options
[ "x$host" = "x-" -o -z "$host" ] && host=0.0.0.0/0
for h in $(separate_list $host); do
hosts="$hosts $interface:$h"
done
routeback=
if [ -n "$options" ]; then
for option in $(separate_list $options); do
case $option in
routeback)
if [ -n "$routeback" ]; then
2005-07-26 01:08:09 +02:00
error_message "WARNING: Duplicate routestopped option ignored: routeback"
2005-07-09 07:45:05 +02:00
else
routeback=Yes
for h in $(separate_list $host); do
run_iptables $1 FORWARD -i $interface -o $interface $(both_ip_ranges $h $h) -j ACCEPT
done
fi
;;
2005-07-09 07:55:29 +02:00
source)
for h in $(separate_list $host); do
source="$source $interface:$h"
done
;;
dest)
for h in $(separate_list $host); do
dest="$dest $interface:$h"
done
;;
2005-07-26 01:08:09 +02:00
critical)
;;
2005-07-09 07:45:05 +02:00
*)
2005-07-26 01:08:09 +02:00
error_message "WARNING: Unknown routestopped option ignored: $option"
2005-07-09 07:45:05 +02:00
;;
esac
done
fi
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
done < $TMP_DIR/routestopped
2005-07-09 07:55:29 +02:00
2005-07-09 07:45:05 +02:00
for host in $hosts; do
interface=${host%:*}
networks=${host#*:}
$IPTABLES $1 INPUT -i $interface $(source_ip_range $networks) -j ACCEPT
2005-09-15 18:11:54 +02:00
[ -z "$ADMINISABSENTMINDED" -o $COMMAND != stop ] && \
2005-07-09 07:45:05 +02:00
run_iptables $1 OUTPUT -o $interface $(dest_ip_range $networks) -j ACCEPT
2005-07-09 07:55:29 +02:00
matched=
if list_search $host $source ; then
run_iptables $1 FORWARD -i $interface $(source_ip_range $networks) -j ACCEPT
matched=Yes
fi
if list_search $host $dest ; then
run_iptables $1 FORWARD -o $interface $(dest_ip_range $networks) -j ACCEPT
matched=Yes
fi
2005-09-19 16:43:22 +02:00
2005-07-09 07:55:29 +02:00
if [ -z "$matched" ]; then
for host1 in $hosts; do
[ "$host" != "$host1" ] && run_iptables $1 FORWARD -i $interface -o ${host1%:*} $(both_ip_ranges $networks ${host1#*:}) -j ACCEPT
done
fi
2005-07-09 07:45:05 +02:00
done
}
2005-07-26 01:08:09 +02:00
process_criticalhosts()
{
local hosts= interface host h options networks criticalhosts=
[ -f $TMP_DIR/routestopped ] || strip_file routestopped
while read interface host options; do
expandv interface host options
[ "x$host" = "x-" -o -z "$host" ] && host=0.0.0.0/0 || host=$(separate_list $host)
if [ -n "$options" ]; then
for option in $(separate_list $options); do
case $option in
routeback|source|dest)
;;
critical)
for h in $host; do
criticalhosts="$criticalhosts $interface:$h"
done
;;
*)
error_message "WARNING: Unknown routestopped option ignored: $option"
;;
esac
done
2005-09-19 16:43:22 +02:00
fi
2005-07-26 01:08:09 +02:00
done < $TMP_DIR/routestopped
if [ -n "$criticalhosts" ]; then
CRITICALHOSTS=$criticalhosts
progress_message "Critical Hosts are:$CRITICALHOSTS"
fi
}
2005-08-02 18:46:30 +02:00
2005-07-26 01:08:09 +02:00
#
# For each entry in the CRITICALHOSTS global list, add INPUT and OUTPUT rules to
# enable traffic to/from those hosts.
#
2005-08-02 18:46:30 +02:00
enable_critical_hosts()
2005-07-26 01:08:09 +02:00
{
for host in $CRITICALHOSTS; do
interface=${host%:*}
networks=${host#*:}
$IPTABLES -A INPUT -i $interface $(source_ip_range $networks) -j ACCEPT
$IPTABLES -A OUTPUT -o $interface $(dest_ip_range $networks) -j ACCEPT
done
}
#
# For each entry in the CRITICALHOSTS global list, delete the INPUT and OUTPUT rules that
# enable traffic to/from those hosts.
#
2005-08-02 18:46:30 +02:00
disable_critical_hosts()
2005-07-26 01:08:09 +02:00
{
for host in $CRITICALHOSTS; do
interface=${host%:*}
networks=${host#*:}
$IPTABLES -D INPUT -i $interface $(source_ip_range $networks) -j ACCEPT
$IPTABLES -D OUTPUT -o $interface $(dest_ip_range $networks) -j ACCEPT
done
}
2002-10-23 18:48:40 +02:00
#
# Stop the Firewall
#
2002-05-01 01:13:15 +02:00
stop_firewall() {
2002-12-05 00:53:03 +01:00
#
# Turn off trace unless we were tracing "stop" or "clear"
#
2005-07-09 06:45:32 +02:00
[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE
case $COMMAND in
2002-12-05 00:53:03 +01:00
stop|clear)
;;
2003-02-27 23:28:06 +01:00
check)
kill $$
exit 2
;;
2002-12-05 00:53:03 +01:00
*)
set +x
2005-07-09 06:45:32 +02:00
2005-09-28 22:28:01 +02:00
[ -n "${RESTOREFILE:=restore}" ]
2005-07-09 06:45:32 +02:00
RESTOREPATH=/var/lib/shorewall/$RESTOREFILE
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
if [ -x $RESTOREPATH ]; then
2005-07-09 07:55:29 +02:00
if [ -x ${RESTOREPATH}-ipsets ]; then
echo Restoring Ipsets...
#
# We must purge iptables to be sure that there are no
# references to ipsets
#
iptables -F
iptables -X
${RESTOREPATH}-ipsets
fi
2005-07-09 06:45:32 +02:00
echo Restoring Shorewall...
2005-07-29 20:32:50 +02:00
if $RESTOREPATH; then
echo "Shorewall restored from $RESTOREPATH"
set_state "Started"
else
set_state "Unknown"
2005-08-02 18:46:30 +02:00
fi
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
my_mutex_off
kill $$
exit 2
fi
2002-12-05 00:53:03 +01:00
;;
esac
2005-07-29 20:32:50 +02:00
set_state "Stopping"
2005-08-23 22:50:48 +02:00
STOPPING="Yes"
2002-05-01 01:13:15 +02:00
2005-08-01 19:17:24 +02:00
TERMINATOR=
2003-02-23 15:10:37 +01:00
2002-05-01 01:13:15 +02:00
deletechain shorewall
run_user_exit stop
[ -n "$MANGLE_ENABLED" ] && \
run_iptables -t mangle -F && \
run_iptables -t mangle -X
2005-08-25 00:39:19 +02:00
[ -n "$RAW_TABLE" ] && \
run_iptables -t raw -F && \
2005-09-19 16:43:22 +02:00
run_iptables -t raw -X
2005-08-25 00:39:19 +02:00
2002-05-01 01:13:15 +02:00
[ -n "$NAT_ENABLED" ] && delete_nat
delete_proxy_arp
2005-07-09 06:45:32 +02:00
[ -n "$CLEAR_TC" ] && delete_tc1
[ -n "$DISABLE_IPV6" ] && disable_ipv6_1
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
process_criticalhosts
if [ -n "$CRITICALHOSTS" ]; then
if [ -z "$ADMINISABSENTMINDED" ]; then
for chain in INPUT OUTPUT; do
setpolicy $chain ACCEPT
done
setpolicy FORWARD DROP
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
deleteallchains
enable_critical_hosts
for chain in INPUT OUTPUT; do
setpolicy $chain DROP
done
else
for chain in INPUT OUTPUT; do
setpolicy $chain ACCEPT
done
setpolicy FORWARD DROP
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
deleteallchains
enable_critical_hosts
setpolicy INPUT DROP
for chain in INPUT FORWARD; do
setcontinue $chain
done
fi
elif [ -z "$ADMINISABSENTMINDED" ]; then
2003-07-30 01:04:04 +02:00
for chain in INPUT OUTPUT FORWARD; do
setpolicy $chain DROP
done
2005-09-19 16:43:22 +02:00
2003-07-30 01:04:04 +02:00
deleteallchains
else
for chain in INPUT FORWARD; do
setpolicy $chain DROP
done
2005-09-19 16:43:22 +02:00
2003-07-30 01:04:04 +02:00
setpolicy OUTPUT ACCEPT
2005-09-19 16:43:22 +02:00
2003-07-30 01:04:04 +02:00
deleteallchains
for chain in INPUT FORWARD; do
setcontinue $chain
done
fi
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
process_routestopped -A
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
$IPTABLES -A INPUT -i lo -j ACCEPT
2003-07-30 01:04:04 +02:00
[ -z "$ADMINISABSENTMINDED" ] && \
2005-07-09 07:45:05 +02:00
$IPTABLES -A OUTPUT -o lo -j ACCEPT
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
for interface in $(find_interfaces_by_option dhcp); do
2005-07-09 07:45:05 +02:00
$IPTABLES -A INPUT -p udp -i $interface --dport 67:68 -j ACCEPT
2003-07-30 01:04:04 +02:00
[ -z "$ADMINISABSENTMINDED" ] && \
2005-07-09 07:45:05 +02:00
$IPTABLES -A OUTPUT -p udp -o $interface --dport 67:68 -j ACCEPT
2005-07-09 06:45:32 +02:00
#
# This might be a bridge
#
2005-07-09 07:45:05 +02:00
$IPTABLES -A FORWARD -p udp -i $interface -o $interface --dport 67:68 -j ACCEPT
2002-05-01 01:13:15 +02:00
done
2005-07-09 06:45:32 +02:00
case "$IP_FORWARDING" in
[Oo][Nn])
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "IP Forwarding Enabled"
;;
[Oo][Ff][Ff])
echo 0 > /proc/sys/net/ipv4/ip_forward
echo "IP Forwarding Disabled!"
;;
esac
2002-05-01 01:13:15 +02:00
2002-07-11 18:15:40 +02:00
run_user_exit stopped
2005-07-29 20:32:50 +02:00
set_state "Stopped"
2002-05-01 01:13:15 +02:00
logger "Shorewall Stopped"
rm -rf $TMP_DIR
2005-07-09 06:45:32 +02:00
case $COMMAND in
2002-05-01 01:13:15 +02:00
stop|clear)
;;
*)
#
# The firewall is being stopped when we were trying to do something
# else. Remove the lock file and Kill the shell in case we're in a
# subshell
#
my_mutex_off
2002-07-06 00:24:40 +02:00
kill $$
;;
2002-05-01 01:13:15 +02:00
esac
}
2002-10-23 18:48:40 +02:00
#
# Remove all rules and remove all user-defined chains
#
2002-05-01 01:13:15 +02:00
clear_firewall() {
stop_firewall
setpolicy INPUT ACCEPT
setpolicy FORWARD ACCEPT
setpolicy OUTPUT ACCEPT
2005-07-09 07:55:29 +02:00
run_iptables -F
echo 1 > /proc/sys/net/ipv4/ip_forward
2005-07-27 22:30:16 +02:00
if qt mywhich ip6tables; then
2005-07-09 06:45:32 +02:00
ip6tables -P INPUT ACCEPT 2> /dev/null
ip6tables -P OUTPUT ACCEPT 2> /dev/null
ip6tables -P FORWARD ACCEPT 2> /dev/null
fi
2002-05-01 01:13:15 +02:00
run_user_exit clear
2005-07-29 20:32:50 +02:00
set_state "Cleared"
2002-05-01 01:13:15 +02:00
logger "Shorewall Cleared"
}
2002-10-23 18:48:40 +02:00
#
# Set up ipsec tunnels
#
2002-05-01 01:13:15 +02:00
setup_tunnels() # $1 = name of tunnels file
{
local inchain
local outchain
2005-08-27 16:50:33 +02:00
2005-07-09 07:45:05 +02:00
2002-10-10 15:29:06 +02:00
setup_one_ipsec() # $1 = gateway $2 = Tunnel Kind $3 = gateway zones
2002-05-01 01:13:15 +02:00
{
2005-07-09 06:45:32 +02:00
local kind=$2 noah=
case $kind in
*:*)
noah=${kind#*:}
[ $noah = noah -o $noah = NOAH ] || fatal_error "Invalid IPSEC modifier $noah in tunnel \"$tunnel\""
kind=${kind%:*}
;;
esac
[ $kind = IPSEC ] && kind=ipsec
2005-08-27 16:50:33 +02:00
options="-m state --state NEW -j ACCEPT"
addrule2 $inchain -p 50 $(source_ip_range $1) -j ACCEPT
addrule2 $outchain -p 50 $(dest_ip_range $1) -j ACCEPT
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
if [ -z "$noah" ]; then
2005-08-27 16:50:33 +02:00
run_iptables -A $inchain -p 51 $(source_ip_range $1) -j ACCEPT
run_iptables -A $outchain -p 51 $(dest_ip_range $1) -j ACCEPT
2005-07-09 06:45:32 +02:00
fi
2002-06-21 17:57:01 +02:00
2005-08-27 16:50:33 +02:00
run_iptables -A $outchain -p udp $(dest_ip_range $1) --dport 500 $options
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
if [ $kind = ipsec ]; then
2005-07-09 07:45:05 +02:00
run_iptables -A $inchain -p udp $(source_ip_range $1) --dport 500 $options
2002-10-10 15:29:06 +02:00
else
2005-07-09 07:45:05 +02:00
run_iptables -A $inchain -p udp $(source_ip_range $1) --dport 500 $options
run_iptables -A $inchain -p udp $(source_ip_range $1) --dport 4500 $options
2002-10-10 15:29:06 +02:00
fi
2005-07-09 06:45:32 +02:00
for z in $(separate_list $3); do
2002-10-01 22:54:42 +02:00
if validate_zone $z; then
2005-07-09 07:45:05 +02:00
addrule ${FW}2${z} -p udp --dport 500 $options
2005-07-09 06:45:32 +02:00
if [ $kind = ipsec ]; then
2005-07-09 07:45:05 +02:00
addrule ${z}2${FW} -p udp --dport 500 $options
2003-01-07 17:26:41 +01:00
else
addrule ${z}2${FW} -p udp --dport 500 $options
addrule ${z}2${FW} -p udp --dport 4500 $options
fi
2002-05-01 01:13:15 +02:00
else
2005-07-09 07:45:05 +02:00
fatal_error "Invalid gateway zone ($z) -- Tunnel \"$tunnel\""
2002-05-01 01:13:15 +02:00
fi
2002-10-01 22:54:42 +02:00
done
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
progress_message " IPSEC tunnel to $gateway defined."
2002-05-01 01:13:15 +02:00
}
2002-06-21 17:57:01 +02:00
setup_one_other() # $1 = TYPE, $2 = gateway, $3 = protocol
2002-05-01 01:13:15 +02:00
{
2005-08-27 16:50:33 +02:00
addrule2 $inchain -p $3 $(source_ip_range $2) -j ACCEPT
addrule2 $outchain -p $3 $(dest_ip_range $2) -j ACCEPT
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
progress_message " $1 tunnel to $2 defined."
2002-10-15 00:26:28 +02:00
}
setup_pptp_client() # $1 = gateway
{
2005-08-27 16:50:33 +02:00
addrule2 $outchain -p 47 $(dest_ip_range $1) -j ACCEPT
addrule2 $inchain -p 47 $(source_ip_range $1) -j ACCEPT
addrule2 $outchain -p tcp --dport 1723 $(dest_ip_range $1) -j ACCEPT
2002-10-15 00:26:28 +02:00
2005-07-09 06:45:32 +02:00
progress_message " PPTP tunnel to $1 defined."
2002-10-15 00:26:28 +02:00
}
2005-07-09 06:45:32 +02:00
setup_pptp_server() # $1 = gateway
2002-10-15 00:26:28 +02:00
{
2005-08-27 16:50:33 +02:00
addrule2 $inchain -p 47 $(source_ip_range $1) -j ACCEPT
addrule2 $outchain -p 47 $(dest_ip_range $1) -j ACCEPT
addrule2 $inchain -p tcp --dport 1723 $(source_ip_range $1) -j ACCEPT
2002-10-15 00:26:28 +02:00
2005-07-09 06:45:32 +02:00
progress_message " PPTP server defined."
2002-05-01 01:13:15 +02:00
}
2003-02-04 17:59:49 +01:00
setup_one_openvpn() # $1 = gateway, $2 = kind[:port]
2003-01-31 20:10:22 +01:00
{
2005-07-09 07:45:05 +02:00
local protocol=udp
local p=1194
2003-01-31 20:10:22 +01:00
case $2 in
2005-07-09 07:45:05 +02:00
*:*:*)
protocol=${2%:*}
protocol=${protocol#*:}
p=${2##*:}
;;
2003-01-31 20:10:22 +01:00
*:*)
p=${2#*:}
;;
esac
2005-08-27 16:50:33 +02:00
addrule2 $inchain -p $protocol $(source_ip_range $1) --dport $p -j ACCEPT
addrule2 $outchain -p $protocol $(dest_ip_range $1) --dport $p -j ACCEPT
2003-01-31 20:10:22 +01:00
2005-07-09 07:45:05 +02:00
progress_message " OPENVPN tunnel to $1:$protocol:$p defined."
2003-01-31 20:10:22 +01:00
}
2005-08-16 23:57:43 +02:00
setup_one_openvpn_server() # $1 = gateway, $2 = kind[:port]
{
local protocol=udp
local p=1194
case $2 in
*:*:*)
protocol=${2%:*}
protocol=${protocol#*:}
p=${2##*:}
;;
*:*)
p=${2#*:}
;;
esac
2005-08-27 16:50:33 +02:00
addrule2 $inchain -p $protocol $(source_ip_range $1) --dport $p -j ACCEPT
addrule2 $outchain -p $protocol $(dest_ip_range $1) --sport $p -j ACCEPT
2005-08-16 23:57:43 +02:00
2005-08-17 00:59:47 +02:00
progress_message " OPENVPN server tunnel from $1:$protocol:$p defined."
2005-08-16 23:57:43 +02:00
}
setup_one_openvpn_client() # $1 = gateway, $2 = kind[:port]
{
local protocol=udp
local p=1194
case $2 in
*:*:*)
protocol=${2%:*}
protocol=${protocol#*:}
p=${2##*:}
;;
*:*)
p=${2#*:}
;;
esac
2005-08-27 21:11:46 +02:00
addrule2 $inchain -p $protocol $(source_ip_range $1) --sport $p -j ACCEPT
2005-08-28 23:44:09 +02:00
addrule2 $outchain -p $protocol $(dest_ip_range $1) --dport $p -j ACCEPT
2005-08-16 23:57:43 +02:00
progress_message " OPENVPN client tunnel to $1:$protocol:$p defined."
}
2003-08-07 01:50:33 +02:00
setup_one_generic() # $1 = gateway, $2 = kind:protocol[:port], $3 = Gateway Zone
2003-08-06 02:06:44 +02:00
{
2005-07-09 06:45:32 +02:00
local protocol
2003-08-06 02:06:44 +02:00
local p=
case $2 in
*:*:*)
p=${2##*:}
2003-08-14 15:57:09 +02:00
protocol=${2%:*}
protocol=${protocol#*:}
2003-08-06 02:06:44 +02:00
;;
*:*)
protocol=${2#*:}
;;
*)
protocol=udp
p=5000
;;
esac
2003-08-07 01:50:33 +02:00
p=${p:+--dport $p}
2003-08-06 02:06:44 +02:00
2005-08-27 16:50:33 +02:00
addrule2 $inchain -p $protocol $(source_ip_range $1) $p -j ACCEPT
addrule2 $outchain -p $protocol $(dest_ip_range $1) $p -j ACCEPT
2003-08-06 02:06:44 +02:00
2005-07-09 06:45:32 +02:00
for z in $(separate_list $3); do
2003-08-07 01:50:33 +02:00
if validate_zone $z; then
2005-08-27 16:50:33 +02:00
addrule ${FW}2${z} -p $protocol $p -j ACCEPT
addrule ${z}2${FW} -p $protocol $p -j ACCEPT
2003-08-07 01:50:33 +02:00
else
2005-08-27 16:50:33 +02:00
error_message "Warning: Invalid gateway zone ($z)" \
2003-08-07 01:50:33 +02:00
" -- Tunnel \"$tunnel\" may encounter problems"
fi
done
2005-07-09 06:45:32 +02:00
progress_message " GENERIC tunnel to $1:$p defined."
2003-08-06 02:06:44 +02:00
}
2002-05-01 01:13:15 +02:00
strip_file tunnels $1
while read kind z gateway z1; do
2002-07-06 00:24:40 +02:00
expandv kind z gateway z1
2005-07-09 06:45:32 +02:00
tunnel="$(echo $kind $z $gateway $z1)"
2002-07-06 00:24:40 +02:00
if validate_zone $z; then
2002-06-21 17:57:01 +02:00
inchain=${z}2${FW}
outchain=${FW}2${z}
2005-07-09 06:45:32 +02:00
gateway=${gateway:-0.0.0.0/0}
2002-06-21 17:57:01 +02:00
case $kind in
2005-07-09 06:45:32 +02:00
ipsec|IPSEC|ipsec:*|IPSEC:*)
setup_one_ipsec $gateway $kind $z1
2002-10-10 15:29:06 +02:00
;;
2005-07-09 06:45:32 +02:00
ipsecnat|IPSECNAT|ipsecnat:*|IPSECNAT:*)
setup_one_ipsec $gateway $kind $z1
2002-06-21 17:57:01 +02:00
;;
ipip|IPIP)
setup_one_other IPIP $gateway 4
;;
gre|GRE)
2002-10-15 00:26:28 +02:00
setup_one_other GRE $gateway 47
;;
2003-04-21 17:12:59 +02:00
6to4|6TO4)
setup_one_other 6to4 $gateway 41
;;
2002-10-15 00:26:28 +02:00
pptpclient|PPTPCLIENT)
setup_pptp_client $gateway
;;
2005-08-02 18:46:30 +02:00
pptpserver|PPTPSERVER)
2005-07-09 06:45:32 +02:00
setup_pptp_server $gateway
2002-06-21 17:57:01 +02:00
;;
2003-02-04 17:59:49 +01:00
openvpn|OPENVPN|openvpn:*|OPENVPN:*)
setup_one_openvpn $gateway $kind
2003-01-31 20:10:22 +01:00
;;
2005-08-16 23:57:43 +02:00
openvpnclient|OPENVPNCLIENT|openvpnclient:*|OPENVPNCLIENT:*)
setup_one_openvpn_client $gateway $kind
;;
openvpnserver|OPENVPNSERVER|openvpnserver:*|OPENVPNSERVER:*)
setup_one_openvpn_server $gateway $kind
;;
2003-08-06 02:06:44 +02:00
generic:*|GENERIC:*)
2003-08-07 01:50:33 +02:00
setup_one_generic $gateway $kind $z1
2003-08-06 02:06:44 +02:00
;;
2002-06-21 17:57:01 +02:00
*)
error_message "Tunnels of type $kind are not supported:" \
"Tunnel \"$tunnel\" Ignored"
;;
esac
else
error_message "Invalid gateway zone ($z)" \
" -- Tunnel \"$tunnel\" Ignored"
2003-02-23 15:10:37 +01:00
fi
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/tunnels
}
2005-07-09 07:45:05 +02:00
#
2005-07-26 01:08:09 +02:00
# Process the ipsec information in the zones file
2005-07-09 07:45:05 +02:00
#
setup_ipsec() {
2005-07-26 01:08:09 +02:00
local zone using_ipsec=
2005-07-09 07:45:05 +02:00
#
# Add a --set-mss rule to the passed chain
#
set_mss1() # $1 = chain, $2 = MSS
{
eval local policy=\$${1}_policy
if [ "$policy" != NONE ]; then
case $COMMAND in
start|restart)
ensurechain $1
run_iptables -I $1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $2
;;
esac
fi
}
#
# Set up rules to set MSS to and/or from zone "$zone"
#
set_mss() # $1 = MSS value, $2 = _in, _out or ""
{
if [ $COMMAND != check ]; then
2005-07-26 01:08:09 +02:00
for z in $ZONES; do
2005-07-09 07:45:05 +02:00
case $2 in
_in)
set_mss1 ${zone}2${z} $1
;;
2005-09-19 16:43:22 +02:00
_out)
2005-07-09 07:45:05 +02:00
set_mss1 ${z}2${zone} $1
;;
*)
set_mss1 ${z}2${zone} $1
set_mss1 ${zone}2${z} $1
;;
esac
done
fi
}
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
do_options() # $1 = _in, _out or "" - $2 = option list
{
local option opts newoptions= val
[ x${2} = x- ] && return
opts=$(separate_list $2)
for option in $opts; do
val=${option#*=}
case $option in
2005-09-19 16:43:22 +02:00
mss=[0-9]*) set_mss $val $1 ;;
2005-07-09 07:45:05 +02:00
strict) newoptions="$newoptions --strict" ;;
next) newoptions="$newoptions --next" ;;
reqid=*) newoptions="$newoptions --reqid $val" ;;
spi=*) newoptions="$newoptions --spi $val" ;;
proto=*) newoptions="$newoptions --proto $val" ;;
mode=*) newoptions="$newoptions --mode $val" ;;
tunnel-src=*) newoptions="$newoptions --tunnel-src $val" ;;
tunnel-dst=*) newoptions="$newoptions --tunnel-dst $val" ;;
reqid!=*) newoptions="$newoptions ! --reqid $val" ;;
spi!=*) newoptions="$newoptions ! --spi $val" ;;
proto!=*) newoptions="$newoptions ! --proto $val" ;;
mode!=*) newoptions="$newoptions ! --mode $val" ;;
tunnel-src!=*) newoptions="$newoptions ! --tunnel-src $val" ;;
tunnel-dst!=*) newoptions="$newoptions ! --tunnel-dst $val" ;;
*) fatal_error "Invalid option \"$option\" for zone $zone" ;;
esac
done
if [ -n "$newoptions" ]; then
2005-07-26 01:08:09 +02:00
[ -n "$POLICY_MATCH" ] || fatal_error "Your kernel and/or iptables does not support policy match"
2005-07-09 07:45:05 +02:00
eval ${zone}_is_complex=Yes
eval ${zone}_ipsec${1}_options=\"${newoptions# }\"
fi
}
2005-07-26 01:08:09 +02:00
case $IPSECFILE in
zones)
f=zones
progress_message "Setting up IPSEC..."
;;
*)
f=$IPSECFILE
strip_file $f
progress_message "Processing $f..."
using_ipsec=Yes
;;
esac
2005-09-02 22:46:53 +02:00
while read zone type options in_options out_options mss; do
expandv zone type options in_options out_options mss
2005-07-09 07:45:05 +02:00
2005-07-26 01:08:09 +02:00
if [ -n "$using_ipsec" ]; then
validate_zone1 $zone || fatal_error "Unknown zone: $zone"
fi
2005-07-09 07:45:05 +02:00
2005-09-02 22:46:53 +02:00
if [ -n "$type" ]; then
if [ -n "$using_ipsec" ]; then
case $type in
No|no)
;;
Yes|yes)
[ -n "$POLICY_MATCH" ] || fatal_error "Your kernel and/or iptables does not support policy match"
eval ${zone}_is_ipsec=Yes
eval ${zone}_is_complex=Yes
2005-10-04 16:54:56 +02:00
eval ${zone}_type=ipsec4
2005-09-02 22:46:53 +02:00
;;
*)
fatal_error "Invalid IPSEC column contents"
;;
esac
fi
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
do_options "" $options
do_options "_in" $in_options
do_options "_out" $out_options
fi
done < $TMP_DIR/$f
2005-09-17 06:05:57 +02:00
}
2005-07-09 07:45:05 +02:00
2005-07-26 01:08:09 +02:00
##
2002-10-23 18:48:40 +02:00
# Setup Proxy ARP
#
2002-05-01 01:13:15 +02:00
setup_proxy_arp() {
2005-07-09 07:45:05 +02:00
local setlist= resetlist=
2002-05-01 01:13:15 +02:00
print_error() {
error_message "Invalid value for HAVEROUTE - ($haveroute)"
error_message "Entry \"$address $interface $external $haveroute\" ignored"
}
2005-07-09 06:45:32 +02:00
print_error1() {
error_message "Invalid value for PERSISTENT - ($persistent)"
error_message "Entry \"$address $interface $external $haveroute $persistent\" ignored"
}
print_warning() {
error_message "PERSISTENT setting ignored - ($persistent)"
error_message "Entry \"$address $interface $external $haveroute $persistent\""
}
2002-05-01 01:13:15 +02:00
setup_one_proxy_arp() {
2005-07-09 06:45:32 +02:00
2002-07-06 00:24:40 +02:00
case $haveroute in
2002-05-01 01:13:15 +02:00
[Nn][Oo])
haveroute=
;;
2002-07-06 00:24:40 +02:00
[Yy][Ee][Ss])
2002-05-01 01:13:15 +02:00
;;
2002-07-06 00:24:40 +02:00
*)
2002-05-01 01:13:15 +02:00
if [ -n "$haveroute" ]; then
2002-07-06 00:24:40 +02:00
print_error
2002-05-01 01:13:15 +02:00
return
2002-07-06 00:24:40 +02:00
fi
2002-05-01 01:13:15 +02:00
;;
esac
2005-07-09 06:45:32 +02:00
case $persistent in
[Nn][Oo])
persistent=
;;
[Yy][Ee][Ss])
[ -z "$haveroute" ] || print_warning
;;
*)
if [ -n "$persistent" ]; then
print_error1
return
fi
;;
esac
2005-08-30 19:42:21 +02:00
if [ $COMMAND != check ]; then
if [ -z "$haveroute" ]; then
2005-09-15 01:01:13 +02:00
ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route replace $address dev $interface"
2005-08-30 19:42:21 +02:00
[ -n "$persistent" ] && haveroute=yes
fi
2005-07-09 06:45:32 +02:00
2005-08-30 19:42:21 +02:00
ensure_and_save_command arp -i $external -Ds $address $external pub
2005-07-09 06:45:32 +02:00
2005-08-30 19:42:21 +02:00
echo $address $interface $external $haveroute >> /var/lib/shorewall/proxyarp
fi
2005-07-09 06:45:32 +02:00
progress_message " Host $address connected to $interface added to ARP on $external"
}
2005-08-30 19:42:21 +02:00
if [ $COMMAND != check ]; then
> /var/lib/shorewall/proxyarp
2005-07-09 06:45:32 +02:00
2005-08-30 19:42:21 +02:00
save_progress_message "Restoring Proxy ARP..."
fi
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
while read address interface external haveroute persistent; do
expandv address interface external haveroute persistent
2005-07-09 07:45:05 +02:00
list_search $interface $setlist || setlist="$setlist $interface"
list_search $external $resetlist || list_search $external $setlist || resetlist="$resetlist $external"
2002-05-01 01:13:15 +02:00
setup_one_proxy_arp
done < $TMP_DIR/proxyarp
2002-07-25 17:05:21 +02:00
2005-08-30 19:42:21 +02:00
if [ $COMMAND != check ]; then
for interface in $resetlist; do
list_search $interface $setlist || \
run_and_save_command "echo 0 > /proc/sys/net/ipv4/conf/$interface/proxy_arp"
done
2005-07-09 07:45:05 +02:00
2005-08-30 19:42:21 +02:00
for interface in $setlist; do
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp"
done
2005-07-09 07:45:05 +02:00
2005-08-30 19:42:21 +02:00
interfaces=$(find_interfaces_by_option proxyarp)
2002-07-25 17:05:21 +02:00
2005-08-30 19:42:21 +02:00
for interface in $interfaces; do
if echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp 2> /dev/null; then
progress_message " Enabled proxy ARP on $interface"
save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp"
else
error_message "WARNING: Unable to enable proxy ARP on $interface"
fi
done
fi
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Set up MAC Verification
#
2002-10-22 20:07:52 +02:00
setup_mac_lists() {
2002-10-23 03:22:48 +02:00
local interface
local mac
2002-10-24 02:47:43 +02:00
local addresses
2002-10-23 03:22:48 +02:00
local address
local chain
2005-07-09 07:45:05 +02:00
local chain1
2002-10-24 02:47:43 +02:00
local macpart
2002-10-23 03:22:48 +02:00
local blob
local hosts
2005-07-09 07:45:05 +02:00
local ipsec
local policy=
2005-10-06 22:01:51 +02:00
create_mac_chain()
{
case $MACLIST_TABLE in
filter)
createchain $1 no
;;
*)
run_iptables -t mangle -N $1
;;
esac
}
have_mac_chain()
{
local result
2005-10-06 22:10:40 +02:00
2005-10-06 22:01:51 +02:00
case $MACLIST_TABLE in
filter)
havechain $1 && result=0 || result=1
;;
*)
mangle_chain_exists $1 && result=0 || result=1
;;
esac
return $result
}
2002-10-23 03:22:48 +02:00
#
# Generate the list of interfaces having MAC verification
#
maclist_interfaces=
2002-10-22 20:07:52 +02:00
2002-10-23 03:22:48 +02:00
for hosts in $maclist_hosts; do
2005-07-09 07:45:05 +02:00
hosts=${hosts#*^}
2005-07-09 06:45:32 +02:00
interface=${hosts%%:*}
2002-10-23 03:22:48 +02:00
if ! list_search $interface $maclist_interfaces; then\
if [ -z "$maclist_interfaces" ]; then
maclist_interfaces=$interface
else
maclist_interfaces="$maclist_interfaces $interface"
fi
fi
done
2005-07-09 06:45:32 +02:00
progress_message "Setting up MAC Verification on $maclist_interfaces..."
2002-10-23 03:22:48 +02:00
#
2005-07-09 07:45:05 +02:00
# Create chains.
2002-10-23 03:22:48 +02:00
#
2002-10-22 20:07:52 +02:00
for interface in $maclist_interfaces; do
2005-07-09 07:45:05 +02:00
chain=$(mac_chain $interface)
2005-10-06 22:01:51 +02:00
create_mac_chain $chain
2005-07-18 00:08:15 +02:00
if [ -n "$MACLIST_TTL" ]; then
chain1=$(macrecent_target $interface)
2005-10-06 22:01:51 +02:00
create_mac_chain $chain1
run_iptables -t $MACLIST_TABLE -A $chain -m recent --rcheck --seconds $MACLIST_TTL --name $chain -j RETURN
run_iptables -t $MACLIST_TABLE -A $chain -j $chain1
run_iptables -t $MACLIST_TABLE -A $chain -m recent --update --name $chain -j RETURN
run_iptables -t $MACLIST_TABLE -A $chain -m recent --set --name $chain
2005-07-18 00:08:15 +02:00
fi
2002-10-22 20:07:52 +02:00
done
2002-10-23 03:22:48 +02:00
#
# Process the maclist file producing the verification rules
#
2002-10-24 02:47:43 +02:00
while read interface mac addresses; do
expandv interface mac addresses
2002-10-23 03:22:48 +02:00
2005-07-09 06:45:32 +02:00
physdev_part=
if [ -n "$BRIDGING" ]; then
case $interface in
*:*)
physdev_part="-m physdev --physdev-in ${interface#*:}"
interface=${interface%:*}
;;
esac
fi
2005-07-18 00:08:15 +02:00
[ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface)
2002-10-22 20:07:52 +02:00
2005-10-06 22:01:51 +02:00
if ! have_mac_chain $chain ; then
2003-02-08 21:58:44 +01:00
fatal_error "No hosts on $interface have the maclist option specified"
2002-10-22 20:07:52 +02:00
fi
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
macpart=$(mac_match $mac)
2002-10-22 20:07:52 +02:00
2002-10-24 02:47:43 +02:00
if [ -z "$addresses" ]; then
2005-10-06 22:01:51 +02:00
run_iptables -t $MACLIST_TABLE -A $chain $macpart $physdev_part -j RETURN
2002-10-24 02:47:43 +02:00
else
2005-07-09 06:45:32 +02:00
for address in $(separate_list $addresses) ; do
2005-10-06 22:01:51 +02:00
run_iptables2 -t $MACLIST_TABLE -A $chain $macpart -s $address $physdev_part -j RETURN
2002-10-24 02:47:43 +02:00
done
fi
2002-10-22 20:07:52 +02:00
done < $TMP_DIR/maclist
2002-10-23 03:22:48 +02:00
#
# Must take care of our own broadcasts and multicasts then terminate the verification
# chains
#
2002-10-22 20:07:52 +02:00
for interface in $maclist_interfaces; do
2005-07-18 00:08:15 +02:00
[ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface)
2003-10-31 16:30:07 +01:00
2005-07-09 06:45:32 +02:00
blob=$(ip link show $interface 2> /dev/null)
2002-10-23 03:22:48 +02:00
[ -z "$blob" ] && \
2003-02-08 21:58:44 +01:00
fatal_error "Interface $interface must be up before Shorewall can start"
2002-10-23 03:22:48 +02:00
2005-07-09 06:45:32 +02:00
ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do
2005-07-15 22:50:01 +02:00
address=${address%/*}
2003-10-31 16:30:07 +01:00
if [ -n "$broadcast" ]; then
2005-10-06 22:01:51 +02:00
run_iptables -t $MACLIST_TABLE -A $chain -s $address -d $broadcast -j RETURN
2003-10-31 16:30:07 +01:00
fi
2002-10-23 03:22:48 +02:00
2005-10-06 22:01:51 +02:00
run_iptables -t $MACLIST_TABLE -A $chain -s $address -d 255.255.255.255 -j RETURN
run_iptables -t $MACLIST_TABLE -A $chain -s $address -d 224.0.0.0/4 -j RETURN
2002-10-22 20:07:52 +02:00
done
2003-05-21 23:36:05 +02:00
if [ -n "$MACLIST_LOG_LEVEL" ]; then
2005-10-06 22:01:51 +02:00
log_rule_limit $MACLIST_LOG_LEVEL $chain $(mac_chain $interface) $MACLIST_DISPOSITION "$LOGLIMIT" "" -A -t $MACLIST_TABLE
2003-05-21 23:36:05 +02:00
fi
2002-10-22 20:07:52 +02:00
2005-10-06 22:01:51 +02:00
run_iptables -t $MACLIST_TABLE -A $chain -j $maclist_target
2002-10-23 03:22:48 +02:00
done
#
# Generate jumps from the input and forward chains
#
2002-10-23 17:58:53 +02:00
for hosts in $maclist_hosts; do
2005-07-09 07:45:05 +02:00
ipsec=${hosts%^*}
hosts=${hosts#*^}
[ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy=
2005-07-09 06:45:32 +02:00
interface=${hosts%%:*}
2002-10-23 17:58:53 +02:00
hosts=${hosts#*:}
2005-10-06 22:01:51 +02:00
case $MACLIST_TABLE in
filter)
for chain in $(first_chains $interface) ; do
run_iptables -A $chain $(match_source_hosts $hosts) -m state --state NEW \
$policy -j $(mac_chain $interface)
done
;;
*)
2005-10-06 22:10:40 +02:00
run_iptables -t mangle -A PREROUTING -i $interface $(match_source_hosts $hosts) -m state --state NEW \
2005-10-06 22:01:51 +02:00
$policy -j $(mac_chain $interface)
;;
esac
2002-10-22 20:07:52 +02:00
done
2003-02-23 15:10:37 +01:00
}
2002-10-23 18:48:40 +02:00
#
# Set up SYN flood protection
#
2002-05-01 01:13:15 +02:00
setup_syn_flood_chain ()
# $1 = policy chain
# $2 = synparams
2005-07-09 06:45:32 +02:00
# $3 = loglevel
2002-05-01 01:13:15 +02:00
{
2005-07-09 06:45:32 +02:00
local chain=@$1
2003-08-13 23:31:02 +02:00
local limit=$2
local limit_burst=
case $limit in
*:*)
limit_burst="--limit-burst ${limit#*:}"
limit=${limit%:*}
;;
esac
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
run_iptables -N $chain
run_iptables -A $chain -m limit --limit $limit $limit_burst -j RETURN
[ -n "$3" ] && \
2005-07-09 07:45:05 +02:00
log_rule_limit $3 $chain $chain DROP "-m limit --limit 5/min --limit-burst 5" "" ""
2005-07-09 06:45:32 +02:00
run_iptables -A $chain -j DROP
2002-05-01 01:13:15 +02:00
}
2005-08-26 21:55:05 +02:00
setup_syn_flood_chains()
{
for chain in $ALL_POLICY_CHAINS; do
eval loglevel=\$${chain}_loglevel
eval synparams=\$${chain}_synparams
[ -n "$synparams" ] && setup_syn_flood_chain $chain $synparams $loglevel
done
}
2002-05-01 01:13:15 +02:00
2002-10-23 18:48:40 +02:00
#
# Delete existing Proxy ARP
#
2002-05-01 01:13:15 +02:00
delete_proxy_arp() {
2005-07-26 01:08:09 +02:00
if [ -f /var/lib/shorewall/proxyarp ]; then
2002-07-06 00:24:40 +02:00
while read address interface external haveroute; do
2002-05-01 01:13:15 +02:00
qt arp -i $external -d $address pub
2005-09-15 01:01:13 +02:00
[ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface
2005-07-26 01:08:09 +02:00
done < /var/lib/shorewall/proxyarp
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
rm -f /var/lib/shorewall/proxyarp
2002-05-01 01:13:15 +02:00
fi
2005-07-26 01:08:09 +02:00
[ -d /var/lib/shorewall ] && touch /var/lib/shorewall/proxyarp
2002-07-25 17:05:21 +02:00
2005-07-09 07:45:05 +02:00
for f in /proc/sys/net/ipv4/conf/*; do
[ -f $f/proxy_arp ] && echo 0 > $f/proxy_arp
2002-07-25 17:05:21 +02:00
done
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Setup Static Network Address Translation (NAT)
#
2002-05-01 01:13:15 +02:00
setup_nat() {
2005-07-09 07:45:05 +02:00
local external= interface= internal= allints= localnat= policyin= policyout=
2002-05-01 01:13:15 +02:00
2005-08-02 18:46:30 +02:00
validate_one() #1 = Variable Name, $2 = Column name, $3 = value
2005-07-09 07:45:05 +02:00
{
case $3 in
Yes|yes)
;;
No|no)
eval ${1}=
;;
*)
[ -n "$3" ] && \
fatal_error "Invalid value ($3) for $2 in entry \"$external $interface $internal $allints $localnat\""
;;
esac
}
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
do_one_nat() {
local add_ip_aliases=$ADD_IP_ALIASES iface=${interface%:*}
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ -n "$add_ip_aliases" ]; then
case $interface in
*:)
interface=${interface%:}
add_ip_aliases=
;;
*)
[ -n "$RETAIN_ALIASES" ] || run_and_save_command qt ip addr del $external dev $iface
;;
esac
2005-07-09 06:45:32 +02:00
else
2005-07-09 07:45:05 +02:00
interface=${interface%:}
2005-07-09 06:45:32 +02:00
fi
2005-07-09 07:45:05 +02:00
validate_one allints "ALL INTERFACES" $allints
validate_one localnat "LOCAL" $localnat
2005-09-19 16:43:22 +02:00
2005-08-30 22:29:42 +02:00
if [ $COMMAND != check ]; then
if [ -n "$allints" ]; then
addnatrule nat_in -d $external $policyin -j DNAT --to-destination $internal
addnatrule nat_out -s $internal $policyout -j SNAT --to-source $external
else
addnatrule $(input_chain $iface) -d $external $policyin -j DNAT --to-destination $internal
addnatrule $(output_chain $iface) -s $internal $policyout -j SNAT --to-source $external
fi
2005-09-17 06:05:57 +02:00
2005-08-30 22:29:42 +02:00
[ -n "$localnat" ] && \
run_iptables2 -t nat -A OUTPUT -d $external $policyout -j DNAT --to-destination $internal
2002-05-01 01:13:15 +02:00
fi
2005-07-09 07:45:05 +02:00
if [ -n "$add_ip_aliases" ]; then
2005-08-23 22:41:18 +02:00
list_search $external $ALIASES_TO_ADD || \
ALIASES_TO_ADD="$ALIASES_TO_ADD $external $interface"
2002-05-01 01:13:15 +02:00
fi
2005-07-09 07:45:05 +02:00
}
#
# At this point, we're just interested in the network translation
#
2005-08-30 22:29:42 +02:00
[ $COMMAND = check ] || > /var/lib/shorewall/nat
2005-07-09 07:45:05 +02:00
if [ -n "$POLICY_MATCH" ]; then
policyin="-m policy --pol none --dir in"
policyout="-m policy --pol none --dir out"
fi
2005-08-30 22:29:42 +02:00
[ -n "$RETAIN_ALIASES" -o $COMMAND = check ] || save_progress_message "Restoring one-to-one NAT..."
2005-07-09 07:45:05 +02:00
while read external interface internal allints localnat; do
expandv external interface internal allints localnat
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
do_one_nat
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
progress_message " Host $internal NAT $external on $interface"
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/nat
}
2002-10-23 18:48:40 +02:00
#
# Delete existing Static NAT
#
2002-05-01 01:13:15 +02:00
delete_nat() {
run_iptables -t nat -F
run_iptables -t nat -X
2005-07-26 01:08:09 +02:00
if [ -f /var/lib/shorewall/nat ]; then
2002-05-01 01:13:15 +02:00
while read external interface; do
qt ip addr del $external dev $interface
2005-07-26 01:08:09 +02:00
done < /var/lib/shorewall/nat
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
rm -f {/var/lib/shorewall}/nat
2002-05-01 01:13:15 +02:00
fi
2005-07-26 01:08:09 +02:00
[ -d /var/lib/shorewall ] && touch /var/lib/shorewall/nat
2002-05-01 01:13:15 +02:00
}
2005-07-09 06:45:32 +02:00
#
# Setup Network Mapping (NETMAP)
#
setup_netmap() {
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
while read type net1 interface net2 ; do
expandv type net1 interface net2
2005-07-09 07:45:05 +02:00
list_search $interface $ALL_INTERFACES || \
2005-07-09 06:45:32 +02:00
fatal_error "Unknown interface $interface in entry \"$type $net1 $interface $net2\""
case $type in
DNAT)
addnatrule $(input_chain $interface) -d $net1 -j NETMAP --to $net2
;;
SNAT)
addnatrule $(output_chain $interface) -s $net1 -j NETMAP --to $net2
;;
*)
fatal_error "Invalid type $type in entry \"$type $net1 $interface $net2\""
;;
esac
progress_message " Network $net1 on $interface mapped to $net2 ($type)"
done < $TMP_DIR/netmap
}
2003-02-24 16:24:55 +01:00
#
# Setup ECN disabling rules
#
setup_ecn() # $1 = file name
{
2003-03-21 20:23:03 +01:00
local interfaces=""
2005-07-09 07:45:05 +02:00
local hosts=
2003-02-24 16:24:55 +01:00
local h
strip_file ecn $1
2003-02-26 00:35:22 +01:00
echo "Processing $1..."
2003-02-24 16:24:55 +01:00
while read interface host; do
expandv interface host
2005-07-09 07:45:05 +02:00
list_search $interface $ALL_INTERFACES || \
2003-03-24 22:56:31 +01:00
startup_error "Unknown interface $interface"
2003-02-24 16:24:55 +01:00
list_search $interface $interfaces || \
interfaces="$interfaces $interface"
2003-02-24 16:35:50 +01:00
[ "x$host" = "x-" ] && host=
2005-07-09 06:45:32 +02:00
for h in $(separate_list ${host:-0.0.0.0/0}); do
2003-02-24 16:24:55 +01:00
hosts="$hosts $interface:$h"
done
done < $TMP_DIR/ecn
if [ -n "$interfaces" ]; then
2005-07-09 06:45:32 +02:00
progress_message "Setting up ECN control on${interfaces}..."
2003-03-24 22:56:31 +01:00
2003-02-24 16:24:55 +01:00
for interface in $interfaces; do
2005-07-09 06:45:32 +02:00
chain=$(ecn_chain $interface)
2003-02-24 16:24:55 +01:00
if mangle_chain_exists $chain; then
flushmangle $chain
else
run_iptables -t mangle -N $chain
run_iptables -t mangle -A POSTROUTING -p tcp -o $interface -j $chain
run_iptables -t mangle -A OUTPUT -p tcp -o $interface -j $chain
fi
done
2003-03-24 22:56:31 +01:00
2003-02-24 16:24:55 +01:00
for host in $hosts; do
interface=${host%:*}
h=${host#*:}
2005-07-09 07:45:05 +02:00
run_iptables -t mangle -A $(ecn_chain $interface) -p tcp $(dest_ip_range $h) -j ECN --ecn-tcp-remove
2005-07-09 06:45:32 +02:00
progress_message " ECN Disabled to $h through $interface"
2003-02-24 16:24:55 +01:00
done
fi
}
2005-08-05 17:52:03 +02:00
#
2005-08-13 23:39:34 +02:00
# Set up an exclusion chain
2005-08-05 17:52:03 +02:00
#
2005-08-14 18:45:48 +02:00
build_exclusion_chain() # $1 = variable to store chain name into $2 = table, $3 = SOURCE exclusion list, $4 = DESTINATION exclusion list
2005-08-05 17:52:03 +02:00
{
2005-08-13 23:39:34 +02:00
local c=excl_${EXCLUSION_SEQ} net
2005-08-05 17:52:03 +02:00
EXCLUSION_SEQ=$(( $EXCLUSION_SEQ + 1 ))
2005-08-13 23:39:34 +02:00
run_iptables -t $2 -N $c
2005-08-05 17:52:03 +02:00
2005-08-13 23:39:34 +02:00
for net in $(separate_list $3); do
run_iptables -t $2 -A $c $(source_ip_range $net) -j RETURN
2005-08-05 17:52:03 +02:00
done
2005-08-13 23:39:34 +02:00
for net in $(separate_list $4); do
run_iptables -t $2 -A $c $(dest_ip_range $net) -j RETURN
2005-08-05 17:52:03 +02:00
done
2005-08-13 23:39:34 +02:00
case $2 in
filter)
eval exists_${c}=Yes
;;
nat)
eval exists_nat_${c}=Yes
;;
esac
eval $1=$c
2005-08-05 17:52:03 +02:00
}
2005-07-09 07:55:29 +02:00
2005-10-06 00:51:29 +02:00
setup_traffic_shaping()
{
2005-10-06 02:41:24 +02:00
local mtu r2q tc_all_devices device mark rate ceil prio options devfile=$(find_file tcdevices) classfile=$(find_file tcclasses)
2005-10-06 00:51:29 +02:00
mtu=1500
r2q=10
rate_to_kbit() {
local rateunit rate
rate=$1
rateunit=$( echo $rate | sed -e 's/[0-9]*//')
rate=$( echo $rate | sed -e 's/[a-z]*//g')
case $rateunit in
kbit)
rate=$rate
;;
mbit)
rate=$(expr $rate \* 1024)
;;
mbps)
rate=$(expr $rate \* 8192)
;;
kbps)
rate=$(expr $rate \* 8)
;;
*)
rate=$(expr $rate / 128)
;;
esac
echo $rate
}
calculate_quantum() {
local rate
rate=$1
rate=$(rate_to_kbit $rate)
rate=$(expr $rate \* 128 / $r2q )
if [ $rate -lt $mtu ] ; then
echo $mtu
else
echo $rate
fi
}
# get given outbandwidth for device
get_outband_for_dev() {
local device inband outband
while read device inband outband; do
expandv device inband outband
tcdev="$device $inband $outband"
if [ "$1" = "$device" ] ; then
echo $outband
return
fi
done < $TMP_DIR/tcdevices
}
check_tcclasses_options() {
while [ $# -gt 1 ]; do
shift
case $1 in
default|tcp-ack|tos-minimize-delay|tos-maximize-throughput|tos-maximize-reliability|tos-minimize-cost|tos-normal-service)
;;
*)
echo $1
return 1
;;
esac
done
return 0
}
get_defmark_for_dev() {
local searchdev searchmark device ceil prio options
searchdev=$1
while read device mark rate ceil prio options; do
expandv device mark rate ceil prio options
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
tcdev="$device $mark $rate $ceil $prio $options"
if [ "$searchdev" = "$device" ] ; then
list_search "default" $options && echo $mark &&return 0
fi
done < $TMP_DIR/tcclasses
return 1
}
check_defmark_for_dev() {
get_defmark_for_dev $1 >/dev/null
}
validate_tcdevices_file() {
2005-10-06 02:41:24 +02:00
echo "Validating $devfile..."
2005-10-06 00:51:29 +02:00
local device local device inband outband
while read device inband outband; do
expandv device inband outband
tcdev="$device $inband $outband"
check_defmark_for_dev $device || fatal_error "Option default is not defined for any class in tcclasses for interface $device"
case $interface in
*:*|+)
fatal_error "Invalid Interface Name: $interface"
;;
esac
list_search $device $devices && fatal_error "Interface $device is defined more than once in tcdevices"
tc_all_devices="$tc_all_devices $device"
done < $TMP_DIR/tcdevices
}
validate_tcclasses_file() {
2005-10-06 02:41:24 +02:00
echo "Validating $classfile..."
2005-10-06 00:51:29 +02:00
local classlist device mark rate ceil prio bandw wrongopt allopts opt
allopts=""
while read device mark rate ceil prio options; do
expandv device mark rate ceil prio options
tcdev="$device $mark $rate $ceil $prio $options"
ratew=$(get_outband_for_dev $device)
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
for opt in $options; do
list_search "$device-$opt" $allopts && fatal_error "option $opt already defined in a chain for interface $device in tcclasses"
allopts="$allopts $device-$opt"
done
wrongopt=$(check_tcclasses_options $options) || fatal_error "unknown option $wrongopt for class iface $device mark $mark in tcclasses file"
if [ -z "$ratew" ] ; then
fatal_error "device $device seems not to be configured in tcdevices"
fi
list_search "$device-$mark" $classlist && fatal_error "Mark $mark for interface $device defined more than once in tcclasses"
classlist="$classlist $device-$mark"
done < $TMP_DIR/tcclasses
}
add_root_tc() {
local defmark
defmark=$(get_defmark_for_dev $device)
run_and_save_command qt tc qdisc del dev $device root
run_and_save_command qt tc qdisc del dev $device ingress
ensure_and_save_command tc qdisc add dev $device root handle 1: htb default 1$defmark
ensure_and_save_command tc class add dev $device parent 1: classid 1:1 htb rate $outband
ensure_and_save_command tc qdisc add dev $device handle ffff: ingress
ensure_and_save_command tc filter add dev $device parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate ${inband} burst 10k drop flowid :1
}
add_tc_class() {
local full
full=$(get_outband_for_dev $device)
full=$(rate_to_kbit $full)
if [ -z "$prio" ] ; then
prio=1
fi
case $rate in
*full*)
rate=$(echo $rate | sed -e "s/full/$full/")
rate="$(($rate))kbit"
;;
esac
case $ceil in
*full*)
ceil=$(echo $ceil | sed -e "s/full/$full/")
ceil="$(($ceil))kbit"
;;
esac
ensure_and_save_command tc class add dev $device parent 1:1 classid 1:1$mark htb rate $rate ceil $ceil prio $prio quantum $(calculate_quantum $rate)
ensure_and_save_command tc qdisc add dev $device parent 1:1$mark handle 1$mark: sfq perturb 10
# add filters
2005-10-06 02:07:06 +02:00
if [ -n "$CLASSIFY_TARGET" ]; then
run_iptables -t mangle -A tcpost -o $device -m mark --mark $mark -j CLASSIFY --set-class 1:1$mark
else
ensure_and_save_command tc filter add dev $device protocol ip parent 1:0 prio 1 handle $mark fw classid 1:1$mark
fi
2005-10-06 16:21:04 +02:00
#options
2005-10-06 00:51:29 +02:00
list_search "tcp-ack" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip protocol 6 0xff match u8 0x05 0x0f at 0 match u16 0x0000 0xffc0 at 2 match u8 0x10 0xff at 33 flowid 1:1$mark
list_search "tos-minimize-delay" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:1$mark
list_search "tos-minimize-cost" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip tos 0x02 0xff flowid 1:1$mark
list_search "tos-maximize-troughput" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip tos 0x08 0xff flowid 1:1$mark
list_search "tos-minimize-reliability" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip tos 0x04 0xff flowid 1:1$mark
list_search "tos-normal-service" $options && ensure_and_save_command tc filter add dev $device parent 1:0 protocol ip prio 10 u32 match ip tos 0x00 0xff flowid 1:1$mark
# tcp
}
2005-10-06 02:41:24 +02:00
strip_file tcdevices $devfile
strip_file tcclasses $classfile
2005-10-06 00:51:29 +02:00
validate_tcdevices_file
validate_tcclasses_file
2005-10-06 00:59:38 +02:00
if [ $COMMAND != check ]; then
if [ -s $TMP_DIR/tcdevices ]; then
save_progress_message "Restoring Traffic Control..."
2005-10-06 02:41:24 +02:00
echo "Processing $devfile..."
2005-10-06 00:59:38 +02:00
while read device inband outband defmark ackmark; do
expandv device inband outband defmark ackmark
tcdev="$device $inband $outband"
add_root_tc
progress_message " TC Device $tcdev Added."
done < $TMP_DIR/tcdevices
fi
2005-10-06 00:51:29 +02:00
2005-10-06 00:59:38 +02:00
if [ -s $TMP_DIR/tcclasses ]; then
2005-10-06 02:41:24 +02:00
echo "Processing $classfile..."
2005-10-06 00:51:29 +02:00
2005-10-06 00:59:38 +02:00
while read device mark rate ceil prio options; do
expandv device mark rate ceil prio options
tcdev="$device $mark $rate $ceil $prio $options"
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
add_tc_class
progress_message " TC Class \"$tcdev\" Added."
done < $TMP_DIR/tcclasses
fi
2005-10-06 00:51:29 +02:00
fi
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 07:45:05 +02:00
# Process a TC Rule - $MARKING_CHAIN is assumed to contain the name of the
2003-01-24 00:18:40 +01:00
# default marking chain
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
process_tc_rule()
{
2005-07-09 07:55:29 +02:00
chain=$MARKING_CHAIN target="MARK --set-mark" marktest=
2005-07-09 07:45:05 +02:00
verify_designator() {
[ "$chain" = tcout ] && \
fatal_error "Chain designator not allowed when source is \$FW; rule \"$rule\""
chain=$1
mark="${mark%:*}"
}
2005-10-04 20:20:28 +02:00
do_ipp2p()
{
2005-10-04 20:46:35 +02:00
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\""
2005-10-05 18:45:50 +02:00
[ "x$port" = "x-" ] && port="ipp2p"
2005-10-04 20:46:35 +02:00
2005-10-04 20:20:28 +02:00
case $proto in
2005-10-05 18:45:50 +02:00
*:*)
proto=${proto#*:}
2005-10-04 20:20:28 +02:00
;;
*)
2005-10-05 18:45:50 +02:00
proto=tcp
2005-10-04 20:20:28 +02:00
;;
esac
2005-10-05 18:45:50 +02:00
r="${r}-p $proto -m ipp2p --${port} "
2005-10-04 20:20:28 +02:00
}
2002-05-01 01:13:15 +02:00
add_a_tc_rule() {
r=
2002-07-06 00:24:40 +02:00
if [ "x$source" != "x-" ]; then
2002-05-01 01:13:15 +02:00
case $source in
2005-07-09 07:55:29 +02:00
$FW:*)
2005-08-16 20:54:11 +02:00
[ $chain = tcpost ] || chain=tcout
2005-08-02 18:46:30 +02:00
r="$(source_ip_range ${source#*:}) "
2005-07-09 07:55:29 +02:00
;;
*.*.*|+*|!+*)
2005-07-09 07:45:05 +02:00
r="$(source_ip_range $source) "
2002-11-09 16:56:29 +01:00
;;
~*)
2005-07-09 06:45:32 +02:00
r="$(mac_match $source) "
2002-11-09 16:56:29 +01:00
;;
$FW)
2005-08-16 20:54:11 +02:00
[ $chain = tcpost ] || chain=tcout
2002-11-09 16:56:29 +01:00
;;
2005-09-19 16:43:22 +02:00
*)
2005-07-09 06:45:32 +02:00
verify_interface $source || fatal_error "Unknown interface $source in rule \"$rule\""
r="$(match_source_dev) $source "
2002-11-09 16:56:29 +01:00
;;
2002-05-01 01:13:15 +02:00
esac
fi
2003-01-24 00:18:40 +01:00
2004-03-04 16:24:59 +01:00
if [ "x${user:--}" != "x-" ]; then
2004-01-22 21:24:56 +01:00
[ "$chain" != tcout ] && \
fatal_error "Invalid use of a user/group: rule \"$rule\""
2005-07-09 07:55:29 +02:00
r="$r-m owner"
2005-09-19 16:43:22 +02:00
2005-07-09 07:55:29 +02:00
case "$user" in
*+*)
r="$r --cmd-owner ${user#*+} "
user=${user%+*}
;;
esac
2004-01-22 21:24:56 +01:00
case "$user" in
*:*)
temp="${user%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && r="$r --uid-owner $temp "
2004-01-22 21:24:56 +01:00
temp="${user#*:}"
[ -n "$temp" ] && r="$r --gid-owner $temp "
;;
*)
2005-07-09 07:55:29 +02:00
[ -n "$user" ] && r="$r --uid-owner $user "
2004-01-22 21:24:56 +01:00
;;
esac
fi
2005-07-09 07:45:05 +02:00
[ -n "$marktest" ] && r="${r}-m ${marktest}--mark $testval "
if [ "x$dest" != "x-" ]; then
case $dest in
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
2005-07-09 07:45:05 +02:00
r="${r}$(dest_ip_range $dest) "
;;
*)
2005-07-10 01:23:45 +02:00
[ "$chain" = tcpre ] && fatal_error "Destination interface is not allowed in the PREROUTING chain"
2005-07-09 07:45:05 +02:00
verify_interface $dest || fatal_error "Unknown interface $dest in rule \"$rule\""
r="${r}$(match_dest_dev $dest) "
;;
esac
fi
2005-08-13 00:11:30 +02:00
multiport=
2005-09-19 16:43:22 +02:00
case $proto in
2005-10-04 20:46:35 +02:00
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
2005-10-04 20:20:28 +02:00
do_ipp2p
2005-10-04 20:00:55 +02:00
;;
2005-09-19 16:43:22 +02:00
icmp|ICMP|1)
r="${r}-p icmp "
2005-09-21 21:10:01 +02:00
[ "x$port" = "x-" ] || r="${r}--icmp-type $port"
2005-09-19 16:43:22 +02:00
;;
*)
2005-09-21 21:05:01 +02:00
[ "x$proto" = "x-" ] && proto=all
[ "x$proto" = "x" ] && proto=all
[ "$proto" = "all" ] || r="${r}-p $proto "
[ "x$port" = "x-" ] || r="${r}--dport $port "
2005-09-19 16:43:22 +02:00
;;
esac
2005-07-09 07:45:05 +02:00
2005-08-13 01:57:35 +02:00
[ "x$sport" = "x-" ] || r="${r}--sport $sport "
2002-05-01 01:13:15 +02:00
2005-08-16 20:54:11 +02:00
if [ -n "${excludesources}${excludedests}" ]; then
build_exclusion_chain chain1 mangle "$excludesources" "$excludedests"
run_iptables2 -t mangle -A $chain $r -j $chain1
run_iptables -t mangle -A $chain1 -j $target $mark
else
run_iptables2 -t mangle -A $chain $r -j $target $mark
fi
2002-05-01 01:13:15 +02:00
}
2003-10-25 02:54:01 +02:00
if [ "$mark" != "${mark%:*}" ]; then
case "${mark#*:}" in
p|P)
2005-07-09 07:45:05 +02:00
verify_designator tcpre
;;
cp|CP)
verify_designator tcpre
target="CONNMARK --set-mark"
2003-10-25 02:54:01 +02:00
;;
f|F)
2005-07-09 07:45:05 +02:00
verify_designator tcfor
;;
cf|CF)
verify_designator tcfor
target="CONNMARK --set-mark"
;;
c|C)
target="CONNMARK --set-mark"
mark=${mark%:*}
2003-10-25 02:54:01 +02:00
;;
*)
2005-07-09 07:45:05 +02:00
chain=tcpost
2005-09-19 16:43:22 +02:00
target="CLASSIFY --set-class"
2003-10-25 02:54:01 +02:00
;;
esac
2005-09-19 16:43:22 +02:00
2003-10-25 02:54:01 +02:00
fi
2005-07-09 07:45:05 +02:00
case $mark in
SAVE)
2005-07-09 07:55:29 +02:00
target="CONNMARK --save-mark --mask 255"
2005-07-09 07:45:05 +02:00
mark=
;;
SAVE/*)
target="CONNMARK --save-mark --mask"
mark=${mark#*/}
2005-07-09 07:55:29 +02:00
verify_mark $mark
2005-07-09 07:45:05 +02:00
;;
RESTORE)
2005-07-09 07:55:29 +02:00
target="CONNMARK --restore-mark --mask 255"
2005-07-09 07:45:05 +02:00
mark=
;;
RESTORE/*)
target="CONNMARK --restore-mark --mask"
mark=${mark#*/}
2005-07-09 07:55:29 +02:00
verify_mark $mark
2005-07-09 07:45:05 +02:00
;;
CONTINUE)
target=RETURN
mark=
;;
2005-07-09 07:55:29 +02:00
*)
if [ "$chain" != tcpost ]; then
verify_mark $mark
fi
;;
2005-09-19 16:43:22 +02:00
esac
2005-07-09 07:45:05 +02:00
case $testval in
-)
;;
!*:C)
marktest="connmark ! "
testval=${testval%:*}
testval=${testval#!}
;;
*:C)
marktest="connmark "
testval=${testval%:*}
;;
!*)
marktest="mark ! "
testval=${testval#!}
;;
*)
[ -n "$testval" ] && marktest="mark "
;;
esac
2005-07-09 07:55:29 +02:00
if [ -n "$marktest" ] ; then
case $testval in
*/*)
verify_mark ${testval%/*}
verify_mark ${testval#*/}
;;
*)
verify_mark $testval
testval=$testval/255
;;
esac
fi
2005-08-16 20:54:11 +02:00
excludesources=
case ${sources:=-} in
*!*!*)
fatal_error "Invalid SOURCE in rule \"$rule\""
;;
!*)
if [ $(list_count $sourcess) -gt 1 ]; then
excludesources=${sources#!}
sources=-
fi
;;
*!*)
excludesources=${sources#*!}
sources=${sources%!*}
;;
esac
excludedests=
case ${dests:=-} in
*!*!*)
fatal_error "Invalid DEST in rule \"$rule\""
;;
!*)
if [ $(list_count $dests) -gt 1 ]; then
excludedests=${dests#*!}
dests=-
fi
;;
*!*)
excludedests=${dests#*!}
dests=${dests%!*}
;;
esac
2005-09-17 06:05:57 +02:00
2005-08-16 20:54:11 +02:00
for source in $(separate_list $sources); do
for dest in $(separate_list $dests); do
2005-07-09 06:45:32 +02:00
for port in $(separate_list ${ports:=-}); do
for sport in $(separate_list ${sports:=-}); do
2002-05-01 01:13:15 +02:00
add_a_tc_rule
done
done
2002-07-06 00:24:40 +02:00
done
2002-05-01 01:13:15 +02:00
done
2005-07-09 06:45:32 +02:00
progress_message " TC Rule \"$rule\" added"
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Setup queuing and classes
#
2002-12-04 22:17:14 +01:00
setup_tc1() {
2002-05-01 01:13:15 +02:00
#
# Create the TC mangle chains
#
2003-02-23 15:10:37 +01:00
2003-01-24 00:18:40 +01:00
run_iptables -t mangle -N tcpre
run_iptables -t mangle -N tcfor
2002-05-01 01:13:15 +02:00
run_iptables -t mangle -N tcout
2005-07-09 07:45:05 +02:00
run_iptables -t mangle -N tcpost
2002-05-01 01:13:15 +02:00
#
# Process the TC Rules File
#
strip_file tcrules
2005-07-09 07:45:05 +02:00
while read mark sources dests proto ports sports user testval; do
expandv mark sources dests proto ports sports user testval
rule=$(echo "$mark $sources $dests $proto $ports $sports $user $testval")
2002-05-01 01:13:15 +02:00
process_tc_rule
done < $TMP_DIR/tcrules
#
# Link to the TC mangle chains from the main chains
#
2003-02-23 15:10:37 +01:00
2005-08-01 19:17:24 +02:00
if [ -n "$ROUTEMARK_INTERFACES" ]; then
#
2005-09-19 16:43:22 +02:00
# Route marks are restored in PREROUTING/OUTPUT prior to these rules. We only send
2005-08-01 19:17:24 +02:00
# packets that are not part of a marked connection to the 'tcpre/tcout' chains
#
run_iptables -t mangle -A PREROUTING -m mark --mark 0 -j tcpre
run_iptables -t mangle -A OUTPUT -m mark --mark 0 -j tcout
else
run_iptables -t mangle -A PREROUTING -j tcpre
run_iptables -t mangle -A OUTPUT -j tcout
fi
2005-07-09 07:45:05 +02:00
run_iptables -t mangle -A FORWARD -j tcfor
run_iptables -t mangle -A POSTROUTING -j tcpost
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
f=$(find_file tcstart)
2002-05-01 01:13:15 +02:00
2005-09-01 17:16:11 +02:00
if [ -f $f ]; then
2005-07-09 07:45:05 +02:00
run_user_exit tcstart
2005-07-09 06:45:32 +02:00
2005-09-01 17:16:11 +02:00
f=$(find_file tcstart) # In case the script used this variable
2005-09-19 16:43:22 +02:00
2005-10-06 00:51:29 +02:00
save_progress_message "Restoring Traffic Control..."
save_command . $f
else
setup_traffic_shaping
2005-07-09 07:45:05 +02:00
fi
2002-05-01 01:13:15 +02:00
}
2002-12-04 22:17:14 +01:00
setup_tc() {
echo "Setting up Traffic Control Rules..."
setup_tc1
}
2002-10-23 18:48:40 +02:00
#
# Clear Traffic Shaping
#
2002-05-01 01:13:15 +02:00
delete_tc()
{
clear_one_tc() {
2005-07-09 06:45:32 +02:00
run_and_save_command "tc qdisc del dev $1 root 2> /dev/null"
2005-08-02 18:46:30 +02:00
run_and_save_command "tc qdisc del dev $1 ingress 2> /dev/null"
2005-07-09 06:45:32 +02:00
}
save_progress_message "Clearing Traffic Control/QOS"
run_user_exit tcclear
run_ip link list | \
while read inx interface details; do
case $inx in
[0-9]*)
clear_one_tc ${interface%:}
;;
*)
;;
esac
done
}
delete_tc1()
{
clear_one_tc() {
tc qdisc del dev $1 root 2> /dev/null
2002-05-01 01:13:15 +02:00
tc qdisc del dev $1 ingress 2> /dev/null
2005-07-09 06:45:32 +02:00
2002-05-01 01:13:15 +02:00
}
run_user_exit tcclear
2002-12-31 17:04:31 +01:00
run_ip link list | \
while read inx interface details; do
case $inx in
[0-9]*)
clear_one_tc ${interface%:}
;;
*)
;;
esac
done
2002-05-01 01:13:15 +02:00
}
2003-02-27 23:28:06 +01:00
#
2003-08-10 03:11:50 +02:00
# Process a record from the accounting file
#
process_accounting_rule() {
rule=
2003-08-10 18:19:36 +02:00
rule2=
2003-08-20 18:54:27 +02:00
jumpchain=
2005-07-09 07:55:29 +02:00
user1=
2005-09-19 16:43:22 +02:00
2003-08-10 18:01:21 +02:00
accounting_error() {
2005-07-26 01:08:09 +02:00
error_message "WARNING: Invalid Accounting rule" $action $chain $source $dest $proto $port $sport $user
2003-08-10 18:01:21 +02:00
}
2005-07-09 06:45:32 +02:00
accounting_interface_error() {
2005-07-26 01:08:09 +02:00
error_message "WARNING: Unknown interface $1 in " $action $chain $source $dest $proto $port $sport $user
2005-07-09 06:45:32 +02:00
}
accounting_interface_verify() {
verify_interface $1 || accounting_interface_error $1
}
2003-08-10 18:01:21 +02:00
jump_to_chain() {
2003-08-20 18:54:27 +02:00
if ! havechain $jumpchain; then
if ! createchain2 $jumpchain No; then
2003-08-10 18:01:21 +02:00
accounting_error
return 2
fi
fi
2005-09-19 16:43:22 +02:00
2003-08-20 18:54:27 +02:00
rule="$rule -j $jumpchain"
2003-08-10 18:01:21 +02:00
}
2003-08-10 03:11:50 +02:00
2005-10-04 20:20:28 +02:00
do_ipp2p() {
2005-10-04 20:46:35 +02:00
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support"
2005-10-04 20:20:28 +02:00
case $proto in
2005-10-05 18:45:50 +02:00
*:*)
proto=${proto#*:}
2005-10-04 20:20:28 +02:00
;;
*)
2005-10-05 18:45:50 +02:00
proto=tcp
2005-10-04 20:20:28 +02:00
;;
esac
2005-10-05 18:45:50 +02:00
rule="$rule -p $proto -m ipp2p --${port:-ipp2p}"
2005-10-04 20:20:28 +02:00
}
2005-07-09 07:55:29 +02:00
2003-08-10 03:11:50 +02:00
case $source in
*:*)
2005-07-09 06:45:32 +02:00
accounting_interface_verify ${source%:*}
2005-07-09 07:55:29 +02:00
rule="$(source_ip_range ${source#*:}) $(match_source_dev ${source%:*})"
2003-08-10 03:11:50 +02:00
;;
2005-07-09 07:55:29 +02:00
*.*.*.*|+*|!+*)
rule="$(source_ip_range $source)"
2003-08-10 03:11:50 +02:00
;;
-|all|any)
;;
*)
2005-07-09 06:45:32 +02:00
if [ -n "$source" ]; then
accounting_interface_verify $source
rule="$(match_source_dev $source)"
fi
2003-08-10 03:11:50 +02:00
;;
esac
2003-08-11 03:36:32 +02:00
[ -n "$dest" ] && case $dest in
2003-08-10 03:11:50 +02:00
*:*)
2005-07-09 06:45:32 +02:00
accounting_interface_verify ${dest%:*}
2005-07-09 07:45:05 +02:00
rule="$rule $(dest_ip_range ${dest#*:}) $(match_dest_dev ${dest%:*})"
2003-08-10 03:11:50 +02:00
;;
2005-07-09 07:55:29 +02:00
*.*.*.*|+*|!*)
2005-07-09 07:45:05 +02:00
rule="$rule $(dest_ip_range $dest)"
2003-08-10 03:11:50 +02:00
;;
-|all|any)
;;
*)
2005-07-09 06:45:32 +02:00
accounting_interface_verify $dest
rule="$rule $(match_dest_dev $dest)"
2003-08-10 03:11:50 +02:00
;;
esac
2003-08-11 03:36:32 +02:00
[ -n "$proto" ] && case $proto in
2003-08-10 03:11:50 +02:00
-|any|all)
;;
2005-10-04 20:46:35 +02:00
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
2005-10-04 20:20:28 +02:00
do_ipp2p
;;
2003-08-10 03:11:50 +02:00
*)
rule="$rule -p $proto"
;;
esac
2005-08-13 00:11:30 +02:00
multiport=
2003-08-11 03:36:32 +02:00
[ -n "$port" ] && case $port in
2003-08-10 03:11:50 +02:00
-|any|all)
;;
*)
2005-08-13 00:11:30 +02:00
if [ -n "$MULTIPORT" ]; then
rule="$rule -m multiport --dports $port"
multiport=Yes
else
2005-09-19 16:43:22 +02:00
rule="$rule --dport $port"
2005-08-13 00:11:30 +02:00
fi
2003-08-10 03:11:50 +02:00
;;
esac
2003-08-11 03:36:32 +02:00
[ -n "$sport" ] && case $sport in
2003-08-10 03:11:50 +02:00
-|any|all)
;;
*)
2005-08-13 00:11:30 +02:00
if [ -n "$MULTIPORT" ]; then
[ -n "$multiport" ] && rule="$rule --sports $sport" || rule="$rule -m multiport --sports $sport"
else
rule="$rule --sport $sport"
fi
2003-08-10 03:11:50 +02:00
;;
esac
2005-07-09 07:45:05 +02:00
[ -n "$user" ] && case $user in
-|any|all)
;;
*)
[ "$chain" != OUTPUT ] && \
fatal_error "Invalid use of a user/group: chain is not OUTPUT but $chain"
2005-07-09 07:55:29 +02:00
rule="$rule -m owner"
user1="$user"
case "$user" in
!*+*)
if [ -n "${user#*+}" ]; then
rule="$rule ! --cmd-owner ${user#*+} "
fi
user1=${user%+*}
2005-09-19 16:43:22 +02:00
;;
2005-07-09 07:55:29 +02:00
*+*)
if [ -n "${user#*+}" ]; then
rule="$rule --cmd-owner ${user#*+} "
fi
user1=${user%+*}
;;
esac
case "$user1" in
!*:*)
if [ "$user1" != "!:" ]; then
temp="${user1#!}"
temp="${temp%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && rule="$rule ! --uid-owner $temp "
2005-07-09 07:55:29 +02:00
temp="${user1#*:}"
[ -n "$temp" ] && rule="$rule ! --gid-owner $temp "
fi
;;
*:*)
if [ "$user1" != ":" ]; then
temp="${user1%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && rule="$rule --uid-owner $temp "
2005-07-09 07:55:29 +02:00
temp="${user1#*:}"
[ -n "$temp" ] && rule="$rule --gid-owner $temp "
fi
;;
!*)
[ "$user1" != "!" ] && rule="$rule ! --uid-owner ${user1#!} "
;;
*)
[ -n "$user1" ] && rule="$rule --uid-owner $user1 "
;;
esac
2005-07-09 07:45:05 +02:00
;;
esac
2003-08-10 18:01:21 +02:00
case $action in
COUNT)
;;
DONE)
rule="$rule -j RETURN"
;;
2003-08-20 18:54:27 +02:00
*:COUNT)
rule2="$rule"
jumpchain=${action%:*}
jump_to_chain || return
;;
JUMP:*)
jumpchain=${action#*:}
2003-08-10 18:01:21 +02:00
jump_to_chain || return
;;
*)
2003-08-20 18:54:27 +02:00
jumpchain=$action
2003-08-10 18:01:21 +02:00
jump_to_chain || return
;;
esac
2003-08-20 18:54:27 +02:00
2005-09-28 22:28:01 +02:00
[ "x${chain:=accounting}" = "x-" ] && chain=accounting
2005-09-17 06:05:57 +02:00
2005-07-09 06:45:32 +02:00
ensurechain1 $chain
2003-08-10 18:12:30 +02:00
2005-07-09 07:45:05 +02:00
if $IPTABLES -A $chain $(fix_bang $rule) ; then
2005-07-09 06:45:32 +02:00
[ -n "$rule2" ] && run_iptables2 -A $jumpchain $rule2
2005-07-09 07:45:05 +02:00
progress_message " Accounting rule" $action $chain $source $dest $proto $port $sport $user Added
2003-08-10 03:11:50 +02:00
else
2003-08-10 18:01:21 +02:00
accounting_error
2003-08-10 03:11:50 +02:00
fi
}
#
# Set up Accounting
#
setup_accounting() # $1 = Name of accounting file
{
2005-08-02 18:46:30 +02:00
2003-08-10 03:11:50 +02:00
echo "Setting up Accounting..."
strip_file accounting $1
2005-07-09 07:45:05 +02:00
while read action chain source dest proto port sport user ; do
expandv action chain source dest proto port sport user
2003-08-20 18:54:27 +02:00
process_accounting_rule
2003-08-10 03:11:50 +02:00
done < $TMP_DIR/accounting
2003-08-10 18:12:30 +02:00
2003-08-11 19:44:23 +02:00
if havechain accounting; then
2003-08-10 18:12:30 +02:00
for chain in INPUT FORWARD OUTPUT; do
2005-08-11 21:53:07 +02:00
run_iptables -I $chain -j accounting
2003-08-10 18:12:30 +02:00
done
fi
2003-08-10 03:11:50 +02:00
}
2005-08-02 18:46:30 +02:00
#
2003-02-27 23:28:06 +01:00
# Check the configuration
#
check_config() {
disclaimer() {
echo
2005-07-09 07:45:05 +02:00
echo "Notice: The 'check' command is provided to catch"
echo " obvious errors in a Shorewall configuration."
echo " It is not designed to catch all possible errors"
echo " so please don't submit problem reports about"
echo " error conditions that 'check' doesn't find"
2003-02-27 23:28:06 +01:00
echo
}
2003-06-27 23:02:52 +02:00
report_capabilities
2003-02-27 23:28:06 +01:00
echo "Verifying Configuration..."
verify_os_version
2003-03-24 22:56:31 +01:00
2005-07-09 07:45:05 +02:00
if [ -n "$BRIDGING" ]; then
[ -n "$PHYSDEV_MATCH" ] || startup_error "BRIDGING=Yes requires Physdev Match support in your Kernel and iptables"
fi
[ "$MACLIST_TTL" = "0" ] && MACLIST_TTL=
2005-07-18 00:08:15 +02:00
if [ -n "$MACLIST_TTL" -a -z "$RECENT_MATCH" ]; then
2005-07-26 01:08:09 +02:00
startup_error "MACLIST_TTL requires the Recent Match capability which is not present in your Kernel and/or iptables"
2005-07-09 07:45:05 +02:00
fi
2003-02-27 23:28:06 +01:00
echo "Determining Zones..."
2003-03-24 22:56:31 +01:00
2003-02-27 23:28:06 +01:00
determine_zones
2003-03-24 22:56:31 +01:00
2005-10-04 16:54:56 +02:00
display_list "IPv4_Zones:" $IPV4_ZONES
[ -n "$IPSEC_ZONES" ] && \
display_list "IPSEC Zones:" $IPSEC_ZONES
2005-10-03 19:39:36 +02:00
display_list "Firewall Zone:" $FW
2003-03-24 22:56:31 +01:00
2005-07-26 01:08:09 +02:00
setup_ipsec
2005-07-09 07:45:05 +02:00
2003-02-27 23:28:06 +01:00
echo "Validating interfaces file..."
2003-03-24 22:56:31 +01:00
2003-02-27 23:28:06 +01:00
validate_interfaces_file
2003-03-24 22:56:31 +01:00
2003-02-27 23:28:06 +01:00
echo "Validating hosts file..."
2003-03-24 22:56:31 +01:00
2003-02-27 23:28:06 +01:00
validate_hosts_file
2003-03-24 22:56:31 +01:00
2003-02-27 23:28:06 +01:00
echo "Determining Hosts in Zones..."
determine_interfaces
determine_hosts
2003-03-24 00:53:10 +01:00
echo "Validating policy file..."
2003-03-24 22:56:31 +01:00
validate_policy
2003-03-24 00:53:10 +01:00
2005-08-30 22:29:42 +02:00
setup_providers $(find_file providers)
2005-07-09 07:55:29 +02:00
validate_blacklist
2005-08-30 19:42:21 +02:00
echo "Validating Proxy ARP"
strip_file proxyarp
setup_proxy_arp
2005-08-30 22:29:42 +02:00
echo "Validating NAT..."
strip_file nat
setup_nat
2005-07-09 06:45:32 +02:00
echo "Pre-validating Actions..."
2003-12-04 03:01:08 +01:00
2005-07-09 06:45:32 +02:00
process_actions1
2003-12-04 03:01:08 +01:00
2003-02-27 23:28:06 +01:00
echo "Validating rules file..."
2005-07-09 06:45:32 +02:00
rules=$(find_file rules)
2003-02-27 23:28:06 +01:00
strip_file rules $rules
process_rules
2003-03-24 22:56:31 +01:00
2005-07-09 06:45:32 +02:00
echo "Validating Actions..."
process_actions2
2005-07-09 07:45:05 +02:00
process_actions3
2005-07-09 06:45:32 +02:00
2005-08-30 17:54:29 +02:00
masq=$(find_file masq)
[ -f $masq ] && setup_masq $masq
2005-10-06 00:59:38 +02:00
setup_traffic_shaping
2003-02-27 23:28:06 +01:00
rm -rf $TMP_DIR
2005-07-09 06:45:32 +02:00
[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE
2003-02-27 23:28:06 +01:00
echo "Configuration Validated"
disclaimer
}
2002-12-04 22:17:14 +01:00
#
# Refresh queuing and classes
#
refresh_tc() {
echo "Refreshing Traffic Control Rules..."
2005-07-09 06:45:32 +02:00
[ -n "$CLEAR_TC" ] && delete_tc1
2002-12-16 20:25:20 +01:00
2002-12-18 22:58:21 +01:00
[ -n "$MARK_IN_FORWARD_CHAIN" ] && chain=tcfor || chain=tcpre
2003-02-23 15:10:37 +01:00
2002-12-18 22:58:21 +01:00
if mangle_chain_exists $chain; then
2002-12-04 22:17:14 +01:00
#
# Flush the TC mangle chains
#
2005-10-05 18:45:50 +02:00
run_iptables -t mangle -F tcfor
run_iptables -t mangle -F tcpre
2002-12-04 22:17:14 +01:00
run_iptables -t mangle -F tcout
2005-10-04 19:04:19 +02:00
run_iptables -t mangle -F tcpost
2002-12-04 22:17:14 +01:00
#
# Process the TC Rules File
#
strip_file tcrules
2005-10-06 00:51:29 +02:00
while read mark sources dests proto ports sports user testval; do
expandv mark sources dests proto ports sports user testval
rule=$(echo "$mark $sources $dests $proto $ports $sports $user $testval")
2003-02-23 15:10:37 +01:00
process_tc_rule
2002-12-04 22:17:14 +01:00
done < $TMP_DIR/tcrules
else
setup_tc1
2005-09-28 20:29:11 +02:00
fi
2005-09-02 01:00:30 +02:00
2005-10-06 00:59:38 +02:00
if [ -n "$TC_ENABLED" ]; then
2005-10-06 00:51:29 +02:00
f=$(find_file tcstart)
2005-09-02 01:00:30 +02:00
2005-10-06 00:51:29 +02:00
if [ -x $f ]; then
export CONFIG_PATH SHOREWALL_DIR
eval $f
fi
else
setup_traffic_shaping
2002-12-04 22:17:14 +01:00
fi
}
2003-12-04 03:01:08 +01:00
#
# Add one Filter Rule from an action -- Helper function for the action file processor
#
# The caller has established the following variables:
2005-07-09 07:45:05 +02:00
# COMMAND = current command. If 'check', we're executing a 'check'
2005-07-09 06:45:32 +02:00
# which only goes through the motions.
# client = SOURCE IP or MAC
# server = DESTINATION IP or interface
# protocol = Protocol
# address = Original Destination Address
# port = Destination Port
# cport = Source Port
# multioption = String to invoke multiport match if appropriate
# action = The chain for this rule
# ratelimit = Optional rate limiting clause
# userandgroup = owner match clause
# logtag = Log tag
2003-12-04 03:01:08 +01:00
#
add_an_action()
{
2005-08-17 23:00:33 +02:00
local chain1
2003-12-04 03:01:08 +01:00
do_ports() {
if [ -n "$port" ]; then
dports="--dport"
if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then
multiport="$multioption"
dports="--dports"
fi
dports="$dports $port"
fi
2005-09-19 16:43:22 +02:00
2003-12-04 03:01:08 +01:00
if [ -n "$cport" ]; then
sports="--sport"
if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then
multiport="$multioption"
sports="--sports"
fi
sports="$sports $cport"
fi
}
2005-07-09 06:45:32 +02:00
interface_error()
{
fatal_error "Unknown interface $1 in rule: \"$rule\""
}
action_interface_verify()
{
verify_interface $1 || interface_error $1
}
2005-08-17 23:00:33 +02:00
handle_exclusion()
{
build_exclusion_chain chain1 filter "$excludesource" "$excludedest"
run_iptables -A $chain $(fix_bang $cli $proto $sports $multiport $dports) $user -j $chain1
cli=
proto=
sports=
multiport=
dports=
user=
}
2005-10-04 20:20:28 +02:00
do_ipp2p() {
2005-10-04 20:46:35 +02:00
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\""
2005-10-05 18:45:50 +02:00
dports="-m ipp2p --${port:-ipp2p}"
2005-10-04 20:20:28 +02:00
case $proto in
2005-10-05 18:45:50 +02:00
ipp2p|IPP2P)
2005-10-04 20:20:28 +02:00
proto=tcp
2005-10-05 18:45:50 +02:00
port=
2005-10-04 20:20:28 +02:00
do_ports
;;
2005-10-04 20:46:35 +02:00
ipp2p:udpIPP2P:UDP)
2005-10-04 20:20:28 +02:00
proto=udp
2005-10-05 18:45:50 +02:00
port=
2005-10-04 20:20:28 +02:00
do_ports
;;
2005-10-04 20:46:35 +02:00
ipp2p:all|IPP2P:ALL)
2005-10-04 20:20:28 +02:00
proto=all
;;
esac
}
2003-12-04 03:01:08 +01:00
# Set source variables. The 'cli' variable will hold the client match predicate(s).
cli=
case "$client" in
-)
;;
*:*)
2005-07-09 06:45:32 +02:00
action_interface_verify ${client%:*}
2005-07-09 07:45:05 +02:00
cli="$(match_source_dev ${client%:*}) $(source_ip_range ${client#*:})"
2003-12-04 03:01:08 +01:00
;;
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
cli="$(source_ip_range $client)"
2003-12-04 03:01:08 +01:00
;;
~*)
2005-07-09 06:45:32 +02:00
cli=$(mac_match $client)
2003-12-04 03:01:08 +01:00
;;
*)
2005-07-09 06:45:32 +02:00
if [ -n "$client" ]; then
action_interface_verify $client
cli="$(match_source_dev $client)"
fi
2003-12-04 03:01:08 +01:00
;;
esac
# Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s).
dest_interface=
serv=
case "$server" in
-)
;;
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
2003-12-04 03:01:08 +01:00
serv=$server
;;
~*)
fatal_error "Rule \"$rule\" - Destination may not be specified by MAC Address"
;;
*)
2005-07-09 06:45:32 +02:00
if [ -n "$server" ]; then
action_interface_verify $server
dest_interface="$(match_dest_dev $server)"
fi
2003-12-04 03:01:08 +01:00
;;
esac
# Setup protocol and port variables
sports=
dports=
proto=$protocol
servport=$serverport
multiport=
2005-08-17 23:00:33 +02:00
chain1=$chain
user="$userandgroup"
2003-12-04 03:01:08 +01:00
[ x$port = x- ] && port=
[ x$cport = x- ] && cport=
case $proto in
tcp|TCP|6)
do_ports
[ "$target" = QUEUE ] && proto="$proto --syn"
;;
udp|UDP|17)
do_ports
;;
icmp|ICMP|1)
[ -n "$port" ] && dports="--icmp-type $port"
;;
2005-10-04 20:46:35 +02:00
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
2005-10-04 20:20:28 +02:00
do_ipp2p
2005-08-31 22:48:22 +02:00
;;
2003-12-04 03:01:08 +01:00
*)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\""
;;
esac
proto="${proto:+-p $proto}"
# Some misc. setup
case "$logtarget" in
LOG)
[ -z "$loglevel" ] && fatal_error "LOG requires log level"
;;
esac
2005-07-09 06:45:32 +02:00
if [ $COMMAND != check ]; then
2005-08-17 23:00:33 +02:00
if [ -n "${excludesource}${excludedest}" ]; then
handle_exclusion
fi
2003-12-04 03:01:08 +01:00
if [ -n "${serv}" ]; then
2005-07-09 06:45:32 +02:00
for serv1 in $(separate_list $serv); do
2005-07-09 07:45:05 +02:00
for srv in $(firewall_ip_range $serv1); do
2003-12-04 03:01:08 +01:00
if [ -n "$loglevel" ]; then
2005-08-17 23:00:33 +02:00
log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \
2005-07-09 07:55:29 +02:00
$(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
2003-12-04 03:01:08 +01:00
fi
2005-09-19 16:43:22 +02:00
2005-08-17 23:00:33 +02:00
run_iptables2 -A $chain1 $proto $multiport $cli $sports \
$(dest_ip_range $srv) $dports $ratelimit $user -j $target
2003-12-04 03:01:08 +01:00
done
done
else
if [ -n "$loglevel" ]; then
2005-08-17 23:00:33 +02:00
log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \
2005-07-09 06:45:32 +02:00
$(fix_bang $proto $sports $multiport $cli $dest_interface $dports)
2003-12-04 03:01:08 +01:00
fi
2005-09-17 06:05:57 +02:00
2005-08-17 23:00:33 +02:00
run_iptables2 -A $chain1 $proto $multiport $cli $dest_interface $sports \
$dports $ratelimit $user -j $target
2003-12-04 03:01:08 +01:00
fi
fi
}
#
2003-12-05 21:34:01 +01:00
# Process a record from an action file for the 'start', 'restart' or 'check' commands
2003-12-04 03:01:08 +01:00
#
2005-07-09 07:45:05 +02:00
process_action() # $1 = chain (Chain to add the rules to)
# $2 = action (The action name for logging purposes)
# $3 = target (The (possibly modified) contents of the TARGET column)
# $4 = clients
# $5 = servers
# $6 = protocol
# $7 = ports
# $8 = cports
# $9 = ratelimit
# $10 = userspec
2003-12-04 03:01:08 +01:00
{
2005-07-09 07:45:05 +02:00
local chain="$1"
local action="$2"
local target="$3"
local clients="$4"
local servers="$5"
local protocol="$6"
local ports="$7"
local cports="$8"
local ratelimit="$9"
local userspec="${10}"
2005-07-09 06:45:32 +02:00
local userandgroup=
local logtag=
2003-12-04 03:01:08 +01:00
if [ -n "$ratelimit" ]; then
case $ratelimit in
-)
ratelimit=
;;
*:*)
ratelimit="-m limit --limit ${ratelimit%:*} --limit-burst ${ratelimit#*:}"
;;
*)
ratelimit="-m limit --limit $ratelimit"
;;
esac
fi
2005-07-09 06:45:32 +02:00
[ "x$userspec" = "x-" ] && userspec=
if [ -n "$userspec" ]; then
2005-07-09 07:55:29 +02:00
userandgroup="-m owner"
2005-09-19 16:43:22 +02:00
2005-07-09 07:55:29 +02:00
case "$userspec" in
!*+*)
if [ -n "${userspec#*+}" ]; then
userandgroup="$userandgroup ! --cmd-owner ${userspec#*+}"
fi
userspec=${userspec%+*}
2005-09-19 16:43:22 +02:00
;;
2005-07-09 07:55:29 +02:00
*+*)
if [ -n "${userspec#*+}" ]; then
userandgroup="$userandgroup --cmd-owner ${userspec#*+}"
fi
userspec=${userspec%+*}
;;
esac
2005-07-09 06:45:32 +02:00
case "$userspec" in
!*:*)
if [ "$userspec" != "!:" ]; then
temp="${userspec#!}"
temp="${temp%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && userandgroup="$userandgroup ! --uid-owner $temp"
2005-07-09 06:45:32 +02:00
temp="${userspec#*:}"
[ -n "$temp" ] && userandgroup="$userandgroup ! --gid-owner $temp"
fi
;;
*:*)
if [ "$userspec" != ":" ]; then
temp="${userspec%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && userandgroup="$userandgroup --uid-owner $temp"
2005-07-09 06:45:32 +02:00
temp="${userspec#*:}"
[ -n "$temp" ] && userandgroup="$userandgroup --gid-owner $temp"
2005-08-02 18:46:30 +02:00
fi
2005-07-09 06:45:32 +02:00
;;
!*)
2005-07-09 07:55:29 +02:00
[ "$userspec" != "!" ] && userandgroup="$userandgroup ! --uid-owner ${userspec#!}"
2005-07-09 06:45:32 +02:00
;;
*)
2005-07-09 07:55:29 +02:00
[ -n "$userspec" ] && userandgroup="$userandgroup --uid-owner $userspec"
2005-07-09 06:45:32 +02:00
;;
esac
2005-07-09 07:55:29 +02:00
[ "$userandgroup" = "-m owner" ] && userandgroup=
2005-07-09 06:45:32 +02:00
fi
2003-12-04 03:01:08 +01:00
# Isolate log level
if [ "$target" = "${target%:*}" ]; then
loglevel=
else
loglevel="${target#*:}"
2005-07-09 06:45:32 +02:00
target="${target%%:*}"
2003-12-04 03:01:08 +01:00
expandv loglevel
2005-07-09 06:45:32 +02:00
if [ "$loglevel" != "${loglevel%:*}" ]; then
logtag="${loglevel#*:}"
loglevel="${loglevel%:*}"
expandv logtag
fi
2005-07-09 07:45:05 +02:00
case $loglevel in
none*)
loglevel=
[ $target = LOG ] && return
;;
esac
loglevel=${loglevel%\!}
2003-12-04 03:01:08 +01:00
fi
2005-07-09 06:45:32 +02:00
2003-12-04 03:01:08 +01:00
logtarget="$target"
case $target in
REJECT)
target=reject
;;
2005-07-09 06:45:32 +02:00
CONTINUE)
target=RETURN
;;
2003-12-04 03:01:08 +01:00
*)
;;
esac
2005-08-17 23:00:33 +02:00
excludesource=
case ${clients:=-} in
*!*!*)
fatal_error "Invalid SOURCE in rule \"$rule\""
;;
!*)
if [ $(list_count $clients) -gt 1 ]; then
excludesource=${clients#!}
clients=
fi
;;
*!*)
excludesource=${clients#*!}
clients=${clients%!*}
;;
esac
2005-09-17 05:49:24 +02:00
2005-08-17 23:00:33 +02:00
excludedest=
case ${servers:=-} in
*!*!*)
fatal_error "Invalid DEST in rule \"$rule\""
;;
!*)
if [ $(list_count $servers) -gt 1 ]; then
excludedest=${servers#*!}
servers=
fi
;;
*!*)
excludedest=${servers#*!}
servers=${servers%!*}
;;
esac
2005-09-17 05:49:24 +02:00
2003-12-04 03:01:08 +01:00
# Generate Netfilter rule(s)
2004-01-30 00:29:50 +01:00
[ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all}
2003-12-04 03:01:08 +01:00
2005-07-09 07:45:05 +02:00
if [ -n "$XMULTIPORT" ] && \
! list_search $protocol "icmp" "ICMP" "1" && \
[ $(( $(list_count $ports) + $(list_count1 $(split $ports ) ) )) -le 16 -a \
2005-08-02 18:46:30 +02:00
$(( $(list_count $cports) + $(list_count1 $(split $cports ) ) )) -le 16 ]
2005-07-09 07:45:05 +02:00
then
#
# Extended MULTIPORT is enabled, and less than
# 16 ports are listed (port ranges count as two ports) - use multiport match.
#
multioption="-m multiport"
2005-08-17 23:00:33 +02:00
for client in $(separate_list $clients); do
for server in $(separate_list $servers); do
2005-07-09 07:45:05 +02:00
#
# add_an_action() modifies these so we must set their values each time
#
port=${ports:=-}
cport=${cports:=-}
add_an_action
done
done
elif [ -n "$MULTIPORT" ] && \
2003-12-04 03:01:08 +01:00
! list_search $protocol "icmp" "ICMP" "1" && \
[ "$ports" = "${ports%:*}" -a \
"$cports" = "${cports%:*}" -a \
2005-07-09 06:45:32 +02:00
$(list_count $ports) -le 15 -a \
$(list_count $cports) -le 15 ]
2003-12-04 03:01:08 +01:00
then
#
# MULTIPORT is enabled, there are no port ranges in the rule and less than
# 16 ports are listed - use multiport match.
#
multioption="-m multiport"
2005-08-17 23:00:33 +02:00
for client in $(separate_list $clients); do
for server in $(separate_list $servers); do
2003-12-04 03:01:08 +01:00
#
2005-07-09 06:45:32 +02:00
# add_an_action() modifies these so we must set their values each time
2003-12-04 03:01:08 +01:00
#
port=${ports:=-}
cport=${cports:=-}
add_an_action
done
done
else
#
# MULTIPORT is disabled or the rule isn't compatible with multiport match
#
multioption=
2005-08-17 23:00:33 +02:00
for client in $(separate_list $clients); do
for server in $(separate_list $servers); do
2005-07-09 06:45:32 +02:00
for port in $(separate_list ${ports:=-}); do
for cport in $(separate_list ${cports:=-}); do
2003-12-04 03:01:08 +01:00
add_an_action
done
done
done
done
fi
#
# Report Result
#
2005-07-09 06:45:32 +02:00
if [ $COMMAND = check ]; then
progress_message " Rule \"$rule\" checked."
2003-12-04 03:01:08 +01:00
else
2005-07-09 06:45:32 +02:00
progress_message " Rule \"$rule\" added."
2003-12-04 03:01:08 +01:00
fi
}
2003-12-05 21:34:01 +01:00
#
2005-07-09 07:45:05 +02:00
# Create and record a log action chain -- Log action chains have names
# that are formed from the action name by prepending a "%" and appending
2005-08-02 18:46:30 +02:00
# a 1- or 2-digit sequence number. In the functions that follow,
2005-07-09 07:45:05 +02:00
# the CHAIN, LEVEL and TAG variable serves as arguments to the user's
# exit. We call the exit corresponding to the name of the action but we
# set CHAIN to the name of the iptables chain where rules are to be added.
# Similarly, LEVEL and TAG contain the log level and log tag respectively.
#
# For each <action>, we maintain two variables:
2005-07-09 06:45:32 +02:00
#
2005-07-09 07:45:05 +02:00
# <action>_actchain - The action chain number.
2005-08-02 18:46:30 +02:00
# <action>_chains - List of ( level[:tag] , chainname ) pairs
2005-07-09 07:45:05 +02:00
#
2005-08-02 18:46:30 +02:00
# The maximum length of a chain name is 30 characters -- since the log
# action chain name is 2-3 characters longer than the base chain name,
# this function truncates the original chain name where necessary before
2005-07-09 07:45:05 +02:00
# it adds the leading "%" and trailing sequence number.
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
createlogactionchain() # $1 = Action Name, $2 = Log Level [: Log Tag ]
2005-07-09 06:45:32 +02:00
{
2005-08-02 18:46:30 +02:00
local actchain= action=$1 level=$2
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
eval actchain=\${${action}_actchain}
2003-12-05 21:34:01 +01:00
2005-07-09 07:45:05 +02:00
case ${#action} in
29|30)
CHAIN=$(echo $action | truncate 28) # %...n makes 30
;;
*)
CHAIN=${action}
;;
esac
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
[ "$COMMAND" != check ] && \
while havechain %${CHAIN}${actchain}; do
actchain=$(($actchain + 1))
[ $actchain -eq 10 -a ${#CHAIN} -eq 28 ] && CHAIN=$(echo $CHAIN | truncate 27) # %...nn makes 30
done
2003-12-04 03:01:08 +01:00
2005-07-09 07:45:05 +02:00
CHAIN=%${CHAIN}${actchain}
2003-12-07 19:15:55 +01:00
2005-07-09 07:45:05 +02:00
eval ${action}_actchain=$(($actchain + 1))
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
if [ $COMMAND != check ]; then
createchain $CHAIN No
LEVEL=${level%:*}
if [ "$LEVEL" != "$level" ]; then
TAG=${level#*:}
else
TAG=
fi
2005-09-19 16:43:22 +02:00
2005-08-29 22:32:16 +02:00
[ none = "${LEVEL%\!}" ] && LEVEL=
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
run_user_exit $1
fi
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
eval ${action}_chains=\"\$${action}_chains $level $CHAIN\"
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
}
#
# Create an action chain and run it's associated user exit
#
createactionchain() # $1 = Action, including log level and tag if any
{
case $1 in
2005-08-29 23:58:24 +02:00
*::*)
fatal_error "Invalid ACTION $1"
;;
2005-07-09 07:45:05 +02:00
*:*:*)
set -- $(split $1)
createlogactionchain $1 $2:$3
;;
*:*)
set -- $(split $1)
createlogactionchain $1 $2
;;
*)
CHAIN=$1
if [ $COMMAND != check ]; then
LEVEL=
TAG=
createchain $CHAIN no
run_user_exit $CHAIN
fi
;;
esac
}
#
# Find the chain that handles the passed action. If the chain cannot be found,
# a fatal error is generated and the function does not return.
#
find_logactionchain() # $1 = Action, including log level and tag if any
{
local fullaction=$1 action=${1%%:*} level= chains=
case $fullaction in
*:*)
level=${fullaction#*:}
;;
*)
if [ $COMMAND != check ]; then
havechain $action || fatal_error "Fatal error in find_logactionchain"
fi
echo $action
return
;;
esac
eval chains="\$${action}_chains"
set -- $chains
while [ $# -gt 0 ]; do
[ "$1" = "$level" ] && { echo $2 ; return ; }
shift;shift
done
fatal_error "Fatal error in find_logactionchain"
}
#
# This function determines the logging for a subordinate action or a rule within a subordinate action
2005-08-02 18:46:30 +02:00
#
2005-07-09 07:45:05 +02:00
merge_levels() # $1=level at which superior action is called, $2=level at which the subordinate rule is called
{
local superior=$1 subordinate=$2
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
set -- $(split $1)
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
case $superior in
*:*:*)
case $2 in
'none!')
2005-08-29 22:32:16 +02:00
echo ${subordinate%%:*}:'none!':$3
2005-07-09 07:45:05 +02:00
return
;;
*'!')
echo ${subordinate%%:*}:$2:$3
return
;;
*)
case $subordinate in
2005-08-29 22:32:16 +02:00
*:*:*)
2005-07-09 07:45:05 +02:00
echo $subordinate
return
;;
2005-08-29 22:32:16 +02:00
*:*)
echo $subordinate:$3
return
;;
2005-07-09 07:45:05 +02:00
*)
echo ${subordinate%%:*}:$2:$3
return
;;
esac
;;
esac
;;
*:*)
case $2 in
'none!')
echo ${subordinate%%:*}:'none!'
return
;;
*'!')
echo ${subordinate%%:*}:$2
return
;;
*)
case $subordinate in
*:*)
echo $subordinate
return
;;
*)
echo ${subordinate%%:*}:$2
return
;;
esac
;;
esac
;;
*)
echo $subordinate
;;
esac
}
2005-07-26 01:08:09 +02:00
# This function substitutes the second argument for the first part of the first argument up to the first colon (":")
#
2005-08-02 18:46:30 +02:00
# Example:
2005-07-26 01:08:09 +02:00
#
2005-08-02 18:46:30 +02:00
# substitute_action DNAT PARAM:info:FTP
2005-07-26 01:08:09 +02:00
#
# produces "DNAT:info:FTP"
#
substitute_action() # $1 = parameter, $2 = action
{
2005-08-30 00:59:01 +02:00
local logpart=${2#*:}
2005-07-26 01:08:09 +02:00
case $2 in
*:*)
echo $1:${logpart%/}
;;
*)
echo $1
;;
esac
}
#
# This function maps old action names into their new macro equivalents
#
map_old_action() # $1 = Potential Old Action
{
local macro= aktion
if [ -n "$MAPOLDACTIONS" ]; then
case $1 in
*/*)
echo $1
return
;;
*)
if [ -f $(find_file $1) ]; then
echo $1
return
fi
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
case $1 in
Allow*)
macro=${1#*w}
aktion=ACCEPT
;;
Drop*)
macro=${1#*p}
aktion=DROP
;;
Reject*)
macro=${1#*t}
aktion=REJECT
;;
*)
echo $1
return
;;
esac
esac
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
if [ -f $(find_file macro.$macro) ]; then
echo $macro/$aktion
fi
fi
echo $1
}
2005-07-09 07:45:05 +02:00
#
# The next three functions implement the three phases of action processing.
#
# The first phase (process_actions1) occurs before the rules file is processed. /usr/share/shorewall/actions.std
# and /etc/shorewall/actions are scanned (in that order) and for each action:
#
# a) The related action definition file is located and scanned.
# b) Forward and unresolved action references are trapped as errors.
2005-08-02 18:46:30 +02:00
# c) A dependency graph is created. For each <action>, the variable 'requiredby_<action>' lists the
2005-07-09 07:45:05 +02:00
# action[:level[:tag]] of each action invoked by <action>.
2005-09-19 16:43:22 +02:00
# d) All actions are listed in the global variable ACTIONS.
2005-07-09 07:45:05 +02:00
# e) Common actions are recorded (in variables of the name <policy>_common) and are added to the global
# USEDACTIONS
#
2005-08-02 18:46:30 +02:00
# As the rules file is scanned, each action[:level[:tag]] is merged onto the USEDACTIONS list. When an <action>
2005-07-09 07:45:05 +02:00
# is merged onto this list, its action chain is created. Where logging is specified, a chain with the name
# %<action>n is used where the <action> name is truncated on the right where necessary to ensure that the total
# length of the chain name does not exceed 30 characters.
#
2005-08-02 18:46:30 +02:00
# The second phase (process_actions2) occurs after the rules file is scanned. The transitive closure of
2005-07-09 07:45:05 +02:00
# USEDACTIONS is generated; again, as new actions are merged onto this list, their action chains are created.
#
# The final phase (process_actions3) is to traverse the USEDACTIONS list populating each chain appropriately
# by reading the action definition files and creating rules. Note that a given action definition file is
# processed once for each unique [:level[:tag]] applied to an invocation of the action.
#
process_actions1() {
2005-09-19 16:43:22 +02:00
2005-10-01 17:55:41 +02:00
ACTIONS="dropBcast allowBcast dropNotSyn rejNotSyn dropInvalid allowInvalid allowinUPnP allowoutUPnP forwardUPnP"
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
USEDACTIONS=
strip_file actions
strip_file actions.std /usr/share/shorewall/actions.std
for inputfile in actions.std actions; do
while read xaction rest; do
[ "x$rest" = x ] || fatal_error "Invalid Action: $xaction $rest"
case $xaction in
*:*)
temp=${xaction#*:}
[ ${#temp} -le 30 ] || fatal_error "Action Name Longer than 30 Characters: $temp"
xaction=${xaction%:*}
case $temp in
ACCEPT|REJECT|DROP|QUEUE)
eval ${temp}_common=$xaction
if [ -n "$xaction" ] && ! list_search $xaction $USEDACTIONS; then
USEDACTIONS="$USEDACTIONS $xaction"
fi
;;
*)
startup_error "Common Actions are only allowed for ACCEPT, DROP, REJECT and QUEUE"
;;
esac
esac
[ -z "$xaction" ] && continue
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
[ "$xaction" = "$(chain_base $xaction)" ] || startup_error "Invalid Action Name: $xaction"
2005-07-09 06:45:32 +02:00
if ! list_search $xaction $ACTIONS; then
f=action.$xaction
fn=$(find_file $f)
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
eval requiredby_${action}=
2005-09-17 06:05:57 +02:00
2005-07-09 06:45:32 +02:00
if [ -f $fn ]; then
echo " Pre-processing $fn..."
strip_file $f $fn
while read xtarget xclients xservers xprotocol xports xcports xratelimit $xuserspec; do
expandv xtarget
temp="${xtarget%%:*}"
2005-07-09 07:45:05 +02:00
case "$temp" in
2005-07-09 06:45:32 +02:00
ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE)
;;
*)
if list_search $temp $ACTIONS; then
2005-07-26 01:08:09 +02:00
eval requiredby=\"\$requiredby_${xaction}\"
list_search $xtarget $requiredby || eval requiredby_${xaction}=\"$requiredby $xtarget\"
2005-07-09 06:45:32 +02:00
else
2005-07-26 01:08:09 +02:00
temp=$(map_old_action $temp)
case $temp in
*/*)
param=${temp#*/}
case $param in
ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE)
;;
*)
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec"
startup_error "Invalid Macro Parameter in rule \"$rule\""
;;
esac
temp=${temp%%/*}
;;
esac
f1=macro.${temp}
fn=$(find_file $f1)
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
if [ ! -f $TMP_DIR/$f1 ]; then
2005-07-27 19:29:20 +02:00
#
# We must only verify macros once to ensure that they don't invoke any non-standard actions
#
2005-07-26 01:08:09 +02:00
if [ -f $fn ]; then
strip_file $f1 $fn
2005-09-19 16:43:22 +02:00
2005-07-27 19:29:20 +02:00
progress_message " ..Expanding Macro $fn..."
2005-09-19 16:43:22 +02:00
2005-07-27 19:29:20 +02:00
while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do
expandv mtarget
temp="${mtarget%%:*}"
case "$temp" in
ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE|PARAM)
;;
*)
rule="$mtarget $mclients $mservers $mprotocol $mports $mcports $mratelimit $muserspec"
startup_error "Invalid TARGET in rule \"$rule\""
2005-08-02 18:46:30 +02:00
esac
2005-07-27 19:29:20 +02:00
done < $TMP_DIR/$f1
2005-09-17 06:05:57 +02:00
2005-07-27 19:29:20 +02:00
progress_message " ..End Macro"
2005-07-26 01:08:09 +02:00
else
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec"
startup_error "Invalid TARGET in rule \"$rule\""
fi
fi
2005-07-09 06:45:32 +02:00
fi
;;
2005-09-17 06:05:57 +02:00
2005-07-09 06:45:32 +02:00
esac
done < $TMP_DIR/$f
else
2005-07-09 07:45:05 +02:00
startup_error "Missing Action File: $f"
2005-07-09 06:45:32 +02:00
fi
2005-09-17 06:05:57 +02:00
2005-07-09 06:45:32 +02:00
ACTIONS="$ACTIONS $xaction"
2003-12-07 19:15:55 +01:00
fi
2005-07-09 06:45:32 +02:00
done < $TMP_DIR/$inputfile
done
}
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
process_actions2() {
2003-12-07 19:15:55 +01:00
2005-08-02 18:46:30 +02:00
local interfaces="$(find_interfaces_by_option upnp)"
2003-12-07 19:15:55 +01:00
2005-07-09 07:45:05 +02:00
if [ -n "$interfaces" ]; then
if ! list_search forwardUPnP $USEDACTIONS; then
2005-07-26 01:08:09 +02:00
error_message "WARNING:Missing forwardUPnP rule (required by 'upnp' interface option on $interfaces)"
2005-07-09 07:45:05 +02:00
USEDACTIONS="$USEDACTIONS forwardUPnP"
fi
fi
progress_message " Generating Transitive Closure of Used-action List..."
2003-12-07 19:15:55 +01:00
2005-07-09 06:45:32 +02:00
changed=Yes
2003-12-04 03:01:08 +01:00
2005-07-09 06:45:32 +02:00
while [ -n "$changed" ]; do
changed=
for xaction in $USEDACTIONS; do
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
eval required=\"\$requiredby_${xaction%%:*}\"
2005-07-26 01:08:09 +02:00
2005-07-09 07:45:05 +02:00
for xaction1 in $required; do
#
# Generate the action that will be passed to process_action by merging the
# logging specified when the action was invoked with the logging in the
# invocation of the subordinate action (usually no logging)
#
xaction2=$(merge_levels $xaction $xaction1)
if ! list_search $xaction2 $USEDACTIONS; then
#
# We haven't seen this one before -- create and record a chain to handle it
#
USEDACTIONS="$USEDACTIONS $xaction2"
createactionchain $xaction2
2005-07-09 06:45:32 +02:00
changed=Yes
fi
done
done
done
2005-07-09 07:45:05 +02:00
}
process_actions3() {
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
for xaction in $USEDACTIONS; do
2005-07-09 07:45:05 +02:00
#
# Find the chain associated with this action:level:tag
#
xchain=$(find_logactionchain $xaction)
#
# Split the action:level:tag
#
set -- $(split $xaction)
xaction1=$1
xlevel=$2
xtag=$3
#
# Handle Builtin actions
#
case $xaction1 in
2005-07-09 06:45:32 +02:00
dropBcast)
if [ "$COMMAND" != check ]; then
2005-08-14 21:26:17 +02:00
if [ -n "$USEPKTTYPE" ]; then
2005-07-09 07:45:05 +02:00
case $xlevel in
none'!')
;;
*)
if [ -n "$xlevel" ]; then
log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -m pkttype --pkt-type broadcast
log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -m pkttype --pkt-type multicast
fi
;;
esac
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
run_iptables -A dropBcast -m pkttype --pkt-type broadcast -j DROP
run_iptables -A dropBcast -m pkttype --pkt-type multicast -j DROP
2005-07-09 06:45:32 +02:00
else
2005-07-09 07:45:05 +02:00
for address in $(find_broadcasts) 255.255.255.255 224.0.0.0/4 ; do
case $xlevel in
none*)
;;
*)
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -d $address
;;
esac
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
run_iptables -A $xchain -d $address -j DROP
done
2005-07-09 06:45:32 +02:00
fi
fi
2005-07-09 07:45:05 +02:00
;;
allowBcast)
if [ "$COMMAND" != check ]; then
2005-08-14 21:26:17 +02:00
if [ -n "$USEPKTTYPE" ]; then
2005-07-09 07:45:05 +02:00
case $xlevel in
none'!')
;;
*)
if [ -n "$xlevel" ]; then
log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -m pkttype --pkt-type broadcast
log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -m pkttype --pkt-type multicast
fi
;;
esac
2005-09-17 06:05:57 +02:00
2005-07-09 07:45:05 +02:00
run_iptables -A allowBcast -m pkttype --pkt-type broadcast -j ACCEPT
run_iptables -A allowBcast -m pkttype --pkt-type multicast -j ACCEPT
else
for address in $(find_broadcasts) 255.255.255.255 224.0.0.0/4 ; do
case $xlevel in
none*)
;;
*)
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -d $address
;;
esac
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
run_iptables -A $xchain -d $address -j ACCEPT
done
fi
fi
;;
2005-07-09 06:45:32 +02:00
dropNotSyn)
2005-07-09 07:45:05 +02:00
if [ "$COMMAND" != check ]; then
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain dropNotSyn DROP "" "$xtag" -A -p tcp ! --syn
run_iptables -A $xchain -p tcp ! --syn -j DROP
fi
2005-07-09 06:45:32 +02:00
;;
rejNotSyn)
2005-07-09 07:45:05 +02:00
if [ "$COMMAND" != check ]; then
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain rejNotSyn REJECT "" "$xtag" -A -p tcp ! --syn
run_iptables -A $xchain -p tcp ! --syn -j REJECT --reject-with tcp-reset
fi
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:45:05 +02:00
dropInvalid)
if [ "$COMMAND" != check ]; then
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain dropInvalid DROP "" "$xtag" -A -m state --state INVALID
run_iptables -A $xchain -m state --state INVALID -j DROP
fi
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:45:05 +02:00
allowInvalid)
if [ "$COMMAND" != check ]; then
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain allowInvalid ACCEPT "" "$xtag" -A -m state --state INVALID
run_iptables -A $xchain -m state --state INVALID -j ACCEPT
fi
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:45:05 +02:00
forwardUPnP)
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:45:05 +02:00
allowinUPnP)
if [ "$COMMAND" != check ]; then
if [ -n "$xlevel" ]; then
log_rule_limit ${xlevel%\!} $xchain allowinUPnP ACCEPT "" "$xtag" -A -p udp --dport 1900
log_rule_limit ${xlevel%\!} $xchain allowinUPnP ACCEPT "" "$xtag" -A -p tcp --dport 49152
fi
run_iptables -A $xchain -p udp --dport 1900 -j ACCEPT
run_iptables -A $xchain -p tcp --dport 49152 -j ACCEPT
fi
2005-07-09 06:45:32 +02:00
;;
2005-07-09 07:45:05 +02:00
allowoutUPnP)
if [ "$COMMAND" != check ]; then
[ -n "$xlevel" ] && \
log_rule_limit ${xlevel%\!} $xchain allowoutUPnP ACCEPT "" "$xtag" -A -m owner --owner-cmd upnpd
run_iptables -A $xchain -m owner --cmd-owner upnpd -j ACCEPT
fi
2005-07-09 06:45:32 +02:00
;;
*)
2005-07-09 07:45:05 +02:00
#
# Not a builtin
#
f=action.$xaction1
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
echo "Processing $(find_file $f) for Chain $xchain..."
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
while read xtarget xclients xservers xprotocol xports xcports xratelimit xuserspec; do
expandv xtarget
#
# Generate the target:level:tag to pass to process_action()
#
xaction2=$(merge_levels $xaction $xtarget)
2005-07-26 01:08:09 +02:00
is_macro=
param=
xtarget1=${xaction2%%:*}
2005-09-17 06:05:57 +02:00
2005-08-02 18:46:30 +02:00
case $xtarget1 in
2005-07-09 07:45:05 +02:00
ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE)
#
# Builtin target -- Nothing to do
#
;;
*)
2005-07-26 01:08:09 +02:00
if list_search $xtarget1 $ACTIONS ; then
#
# An Action -- Replace the target from the file
# -- with the one generated above
xtarget=$xaction2
#
# And locate the chain for that action:level:tag
#
xaction2=$(find_logactionchain $xtarget)
else
is_macro=yes
fi
2005-07-09 07:45:05 +02:00
;;
esac
expandv xclients xservers xprotocol xports xcports xratelimit xuserspec
2005-07-26 01:08:09 +02:00
if [ -n "$is_macro" ]; then
2005-07-09 07:45:05 +02:00
2005-07-26 01:08:09 +02:00
xtarget1=$(map_old_action $xtarget1)
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
case $xtarget1 in
*/*)
param=${xtarget1#*/}
xtarget1=${xtarget1%%/*}
;;
esac
progress_message "..Expanding Macro $(find_file macro.$xtarget1)..."
while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do
expandv mtarget mclients mservers mprotocol mports mcports mratelimit muserspec
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
mtarget=$(merge_levels $xaction2 $mtarget)
case $mtarget in
PARAM|PARAM:*)
[ -n "$param" ] && mtarget=$(substitute_action $param $mtarget) || fatal_error "PARAM requires that a parameter be supplied in macro invocation"
;;
esac
2005-09-17 06:05:57 +02:00
2005-07-26 01:08:09 +02:00
if [ -n "$mclients" ]; then
case $mclients in
-)
mclients=${xclients}
;;
*)
mclients=${mclients}:${xclients}
;;
esac
else
mclients=${xclients}
fi
if [ -n "$mservers" ]; then
case $mservers in
-)
mservers=${xservers}
;;
*)
mservers=${mservers}:${xservers}
;;
esac
else
mservers=${xserverss}
fi
[ -n "$xprotocol" ] && [ "x${xprotocol}" != x- ] && mprotocol=$xprotocol
[ -n "$xports" ] && [ "x${xports}" != x- ] && mports=$xports
[ -n "$xcports" ] && [ "x${xcports}" != x- ] && mcports=$xcports
[ -n "$xratelimit" ] && [ "x${xratelimit}" != x- ] && mratelimit=$xratelimit
[ -n "$xuserspec" ] && [ "x${xuserspec}" != x- ] && muserspec=$xuserspec
rule="$mtarget ${mclients:=-} ${mservers:=-} ${mprotocol:=-} ${mports:=-} ${mcports:=-} ${mratelimit:-} ${muserspec:=-}"
process_action $xchain $xaction1 $mtarget $mclients $mservers $mprotocol $mports $mcports $mratelimit $muserspec
done < $TMP_DIR/macro.$xtarget1
progress_message "..End Macro"
else
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec"
process_action $xchain $xaction1 $xaction2 $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec
fi
2005-07-09 06:45:32 +02:00
done < $TMP_DIR/$f
;;
esac
done
2003-12-04 03:01:08 +01:00
}
2005-09-17 06:05:57 +02:00
2002-10-23 18:48:40 +02:00
#
# Add a NAT rule - Helper function for the rules file processor
#
# The caller has established the following variables:
2005-07-09 07:45:05 +02:00
# COMMAND = The current command -- if 'check', we just go through
2003-02-27 23:28:06 +01:00
# the motions.
2002-10-23 18:48:40 +02:00
# cli = Source IP, interface or MAC Specification
# serv = Destination IP Specification
# servport = Port the server is listening on
# dest_interface = Destination Interface Specification
# proto = Protocol Specification
# addr = Original Destination Address
# dports = Destination Port Specification. 'dports' may be changed
# by this function
# cport = Source Port Specification
# multiport = String to invoke multiport match if appropriate
2003-08-23 20:14:59 +02:00
# ratelimit = Optional rate limiting clause
2005-07-09 06:45:32 +02:00
# userandgroup = -m owner match to limit the rule to a particular user and/or group
# logtag = Log tag
2005-08-15 19:35:45 +02:00
# excludesource = Source Exclusion List
2002-10-23 18:48:40 +02:00
#
2002-06-19 23:51:36 +02:00
add_nat_rule() {
local chain
2003-05-31 17:29:14 +02:00
local excludedests=
2002-06-19 23:51:36 +02:00
2003-06-02 20:08:35 +02:00
# Be sure we can NAT
2003-02-23 15:10:37 +01:00
2003-05-31 17:29:14 +02:00
if [ -z "$NAT_ENABLED" ]; then
fatal_error "Rule \"$rule\" requires NAT which is disabled"
fi
2002-05-18 15:45:23 +02:00
2002-06-19 23:51:36 +02:00
# Parse SNAT address if any
2002-05-18 15:45:23 +02:00
2002-06-19 23:51:36 +02:00
if [ "$addr" != "${addr%:*}" ]; then
2005-07-09 07:45:05 +02:00
fatal_error "SNAT may no longer be specified in a DNAT rule; use /etc/shorewall/masq instead"
2002-06-19 23:51:36 +02:00
fi
2002-05-18 15:45:23 +02:00
2002-06-19 23:51:36 +02:00
# Set original destination address
2002-05-18 15:45:23 +02:00
2002-07-09 17:44:49 +02:00
case $addr in
all)
addr=
;;
detect)
2003-05-31 17:29:14 +02:00
addr=
if [ -n "$DETECT_DNAT_IPADDRS" -a "$source" != "$FW" ]; then
eval interfaces=\$${source}_interfaces
for interface in $interfaces; do
2005-07-09 07:45:05 +02:00
addr=${addr:+$addr,}$(find_first_interface_address $interface)
2003-05-31 17:29:14 +02:00
done
fi
;;
!*)
2005-07-09 06:45:32 +02:00
if [ $(list_count $addr) -gt 1 ]; then
2005-08-05 17:52:03 +02:00
excludedests="${addr#\!}"
2003-05-31 17:29:14 +02:00
addr=
fi
;;
2002-07-09 17:44:49 +02:00
esac
addr=${addr:-0.0.0.0/0}
2002-05-18 15:45:23 +02:00
2002-06-19 23:51:36 +02:00
# Select target
2005-07-09 07:45:05 +02:00
if [ "$logtarget" = SAME ]; then
[ -n "$servport" ] && fatal_error "Port mapping not allowed in SAME rules"
serv1=
for srv in $(separate_list $serv); do
serv1="$serv1 --to ${srv}"
done
target1="SAME $serv1"
elif [ -n "$serv" ]; then
2002-06-19 23:51:36 +02:00
servport="${servport:+:$servport}"
2003-07-01 22:29:01 +02:00
serv1=
2005-07-09 06:45:32 +02:00
for srv in $(separate_list $serv); do
2003-07-01 22:29:01 +02:00
serv1="$serv1 --to-destination ${srv}${servport}"
done
target1="DNAT $serv1"
2002-06-19 23:51:36 +02:00
else
target1="REDIRECT --to-port $servport"
fi
2005-08-16 18:31:55 +02:00
if [ $source = $FW ]; then
[ -n "$excludezones" ] && fatal_error "Invalid Source in rule \"$rule\""
fi
2002-06-19 23:51:36 +02:00
# Generate nat table rules
2005-07-09 06:45:32 +02:00
if [ $COMMAND != check ]; then
2003-02-27 23:28:06 +01:00
if [ "$source" = "$FW" ]; then
2005-08-15 19:35:45 +02:00
if [ -n "${excludesource}${excludedests}" ]; then
build_exclusion_chain chain nat "$excludesource" $excludedests
2005-08-11 03:40:50 +02:00
2005-07-09 06:45:32 +02:00
for adr in $(separate_list $addr); do
2005-07-09 07:45:05 +02:00
run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain
2003-07-14 21:43:32 +02:00
done
2003-06-01 20:14:57 +02:00
2003-05-31 18:34:17 +02:00
if [ -n "$loglevel" ]; then
2005-08-06 18:58:18 +02:00
log_rule_limit $loglevel $chain OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat
2003-05-31 18:34:17 +02:00
fi
2003-08-13 19:07:05 +02:00
addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection
2003-05-31 18:34:17 +02:00
else
2005-07-09 06:45:32 +02:00
for adr in $(separate_list $addr); do
2003-07-14 21:51:25 +02:00
if [ -n "$loglevel" ]; then
2005-07-09 07:45:05 +02:00
log_rule_limit $loglevel OUTPUT OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat \
$(fix_bang $proto $cli $sports $userandgroup $(dest_ip_range $adr) $multiport $dports)
2003-07-14 21:51:25 +02:00
fi
2003-07-14 22:25:03 +02:00
2005-07-09 07:45:05 +02:00
run_iptables2 -t nat -A OUTPUT $ratelimit $proto $sports $userandgroup $(dest_ip_range $adr) $multiport $dports -j $target1
2003-05-31 18:34:17 +02:00
done
fi
2003-02-27 23:28:06 +01:00
else
2005-08-16 18:31:55 +02:00
if [ -n "${excludesource}${excludedests}${excludezones}" ]; then
2005-08-15 19:35:45 +02:00
build_exclusion_chain chain nat "$excludesource" $excludedests
2005-08-11 03:40:50 +02:00
2005-07-09 06:45:32 +02:00
for adr in $(separate_list $addr); do
2005-07-09 07:45:05 +02:00
addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain
2003-07-14 21:43:32 +02:00
done
2005-09-19 16:17:29 +02:00
for z in $(separate_list $excludezones); do
eval hosts=\$${z}_hosts
for host in $hosts; do
addnatrule $chain $(match_source_hosts ${host#*:}) -j RETURN
done
done
2005-09-19 16:43:22 +02:00
2003-07-14 21:43:32 +02:00
if [ -n "$loglevel" ]; then
2005-08-06 18:58:18 +02:00
log_rule_limit $loglevel $chain $(dnat_chain $source) $logtarget "$ratelimit" "$logtag" -A -t nat
2003-07-14 21:43:32 +02:00
fi
2003-05-31 17:29:14 +02:00
2003-08-13 19:07:05 +02:00
addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection
2003-05-31 17:29:14 +02:00
else
2005-08-06 18:58:18 +02:00
chain=$(dnat_chain $source)
2005-07-09 06:45:32 +02:00
for adr in $(separate_list $addr); do
2003-05-31 17:29:14 +02:00
if [ -n "$loglevel" ]; then
ensurenatchain $chain
2005-07-09 07:45:05 +02:00
log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat \
$(fix_bang $proto $cli $sports $(dest_ip_range $adr) $multiport $dports)
2003-05-31 17:29:14 +02:00
fi
2005-09-19 16:43:22 +02:00
2003-08-13 19:07:05 +02:00
addnatrule $chain $proto $ratelimit $cli $sports \
2003-05-31 17:29:14 +02:00
-d $adr $multiport $dports -j $target1
done
fi
2002-05-18 15:45:23 +02:00
fi
2002-06-19 23:51:36 +02:00
fi
2002-05-18 15:45:23 +02:00
2002-06-19 23:51:36 +02:00
# Replace destination port by the new destination port
2002-08-14 18:01:32 +02:00
if [ -n "$servport" ]; then
if [ -z "$multiport" ]; then
dports="--dport ${servport#*:}"
else
dports="--dports ${servport#*:}"
fi
fi
2002-06-19 23:51:36 +02:00
2003-08-13 19:07:05 +02:00
[ "x$addr" = "x0.0.0.0/0" ] && addr=
ratelimit=
2002-06-19 23:51:36 +02:00
}
2002-05-18 15:45:23 +02:00
2002-10-23 18:48:40 +02:00
#
2005-08-15 19:35:45 +02:00
# Process a record from the rules file for the 'start', 'restart' or 'check' commands
2002-10-23 18:48:40 +02:00
#
2005-08-15 19:35:45 +02:00
process_rule() # $1 = target
# $2 = clients
# $3 = servers
# $4 = protocol
# $5 = ports
# $6 = cports
# $7 = address
# $8 = ratelimit
# $9 = userspec
2002-06-19 23:51:36 +02:00
{
2005-08-15 19:35:45 +02:00
local target="$1"
local clients="$2"
local servers="$3"
local protocol="$4"
local ports="$5"
local cports="$6"
local address="$7"
local ratelimit="$8"
local userspec="$9"
local userandgroup=
local logtag=
local nonat=
#
# Add one Filter Rule
#
# The caller has established the following variables:
# COMMAND = current command. If 'check', we're executing a 'check'
# which only goes through the motions.
# client = SOURCE IP or MAC
# server = DESTINATION IP or interface
# protocol = Protocol
# address = Original Destination Address
# port = Destination Port
# cport = Source Port
# multioption = String to invoke multiport match if appropriate
# servport = Port the server listens on
2005-08-16 18:54:03 +02:00
# chain = The canonical chain for this rule
2005-08-15 19:35:45 +02:00
# logchain = The chain that should be mentioned in log messages
# ratelimit = Optional rate limiting clause
# userandgroup = -m owner clause
# userspec = User name
# logtag = Log tag
# policy = Applicable Policy
#
2005-08-15 22:49:06 +02:00
add_a_rule()
2005-08-15 19:35:45 +02:00
{
2005-08-15 22:49:06 +02:00
local natrule=
2005-08-15 19:35:45 +02:00
do_ports() {
if [ -n "$port" ]; then
dports="--dport"
if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then
multiport="$multioption"
dports="--dports"
fi
dports="$dports $port"
2003-10-10 00:33:44 +02:00
fi
2005-09-19 16:43:22 +02:00
2005-08-15 19:35:45 +02:00
if [ -n "$cport" ]; then
sports="--sport"
if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then
multiport="$multioption"
sports="--sports"
fi
sports="$sports $cport"
2003-10-10 00:33:44 +02:00
fi
2005-08-15 19:35:45 +02:00
}
2003-10-10 00:33:44 +02:00
2005-08-15 19:35:45 +02:00
interface_error()
{
fatal_error "Unknown interface $1 in rule: \"$rule\""
}
2005-09-19 16:43:22 +02:00
2005-08-15 19:35:45 +02:00
rule_interface_verify()
{
verify_interface $1 || interface_error $1
}
2005-07-09 06:45:32 +02:00
2005-08-15 20:33:51 +02:00
handle_exclusion()
{
2005-08-15 22:49:06 +02:00
build_exclusion_chain chain filter "$excludesource" "$excludedest"
2005-08-15 22:16:34 +02:00
if [ -n "$addr" -a -n "$CONNTRACK_MATCH" ]; then
for adr in $(separate_list $addr); do
2005-08-26 21:55:05 +02:00
run_iptables -A $logchain $state $(fix_bang $proto $sports $multiport $dports) $user -m conntrack --ctorigdst $adr -j $chain
2005-08-15 22:16:34 +02:00
done
2005-08-15 20:33:51 +02:00
addr=
else
2005-08-26 21:55:05 +02:00
run_iptables -A $state $logchain $(fix_bang $cli $proto $sports $multiport $dports) $user -j $chain
2005-08-15 20:33:51 +02:00
fi
2005-08-15 22:21:52 +02:00
cli=
2005-08-15 20:33:51 +02:00
proto=
sports=
multiport=
dports=
2005-08-15 22:16:34 +02:00
user=
2005-08-26 21:55:05 +02:00
state=
2005-08-15 20:33:51 +02:00
}
2005-10-04 20:20:28 +02:00
do_ipp2p() {
2005-10-04 20:46:35 +02:00
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\""
2005-10-05 18:45:50 +02:00
dports="-m ipp2p --${port:-ipp2p}"
2005-10-04 20:20:28 +02:00
case $proto in
2005-10-04 20:46:35 +02:00
ipp2p|IPP2P|ipp2p:tcp|IPP2P:TCP)
2005-10-04 20:20:28 +02:00
port=
proto=tcp
do_ports
;;
2005-10-04 20:46:35 +02:00
ipp2p:udp|IPP2P:UDP)
2005-10-04 20:20:28 +02:00
port=
proto=udp
do_ports
;;
2005-10-04 20:46:35 +02:00
ipp2p:all|IPP2P:ALL)
2005-10-04 20:20:28 +02:00
port=
proto=all
;;
*)
2005-10-04 20:46:35 +02:00
fatal_error "Invalid IPP2P protocol ${proto#*:}. Rule: \"$rule\""
2005-10-04 20:20:28 +02:00
;;
esac
}
2005-08-15 19:35:45 +02:00
# Set source variables. The 'cli' variable will hold the client match predicate(s).
2005-07-09 06:45:32 +02:00
2005-08-15 19:35:45 +02:00
cli=
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
case "$client" in
-)
;;
*:*)
rule_interface_verify ${client%:*}
cli="$(match_source_dev ${client%:*}) $(source_ip_range ${client#*:})"
;;
*.*.*|+*)
cli="$(source_ip_range $client)"
;;
~*)
cli=$(mac_match $client)
;;
*)
if [ -n "$client" ]; then
rule_interface_verify $client
cli="$(match_source_dev $client)"
fi
;;
esac
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
# Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s).
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
dest_interface=
serv=
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
case "$server" in
-)
;;
*.*.*|+*)
serv=$server
;;
~*)
fatal_error "Rule \"$rule\" - Destination may not be specified by MAC Address"
;;
*)
if [ -n "$server" ]; then
[ -n "$nonat" ] && fatal_error "Destination interface not allowed with $logtarget"
rule_interface_verify $server
dest_interface="$(match_dest_dev $server)"
fi
;;
esac
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
# Setup protocol and port variables
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
sports=
dports=
proto=$protocol
addr=$address
servport=$serverport
multiport=
2005-08-15 22:16:34 +02:00
user="$userandgroup"
2005-09-19 16:43:22 +02:00
2005-08-15 22:49:06 +02:00
# Restore $chain to the canonical chain.
chain=$logchain
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
[ x$port = x- ] && port=
[ x$cport = x- ] && cport=
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
case $proto in
tcp|TCP|6)
do_ports
[ "$target" = QUEUE ] && proto="$proto --syn"
;;
udp|UDP|17)
do_ports
;;
icmp|ICMP|1)
[ -n "$port" ] && dports="--icmp-type $port"
;;
all|ALL)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"all\"; rule: \"$rule\""
proto=
;;
2005-10-04 20:46:35 +02:00
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
2005-10-04 20:20:28 +02:00
do_ipp2p
2005-10-04 20:00:55 +02:00
;;
2005-08-15 19:35:45 +02:00
*)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\""
;;
esac
2003-06-28 17:22:22 +02:00
2005-08-15 19:35:45 +02:00
proto="${proto:+-p $proto}"
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
# Some misc. setup
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
case "$logtarget" in
2005-09-19 16:43:22 +02:00
ACCEPT|DROP|REJECT|CONTINUE)
2005-08-15 22:16:34 +02:00
if [ -z "$proto" -a -z "$cli" -a -z "$serv" -a -z "$servport" -a -z "$user" -a -z "$excludesource" -a -z "$excludedest" ] ; then
2005-08-15 19:35:45 +02:00
error_message "Warning -- Rule \"$rule\" is a POLICY"
error_message " -- and should be moved to the policy file"
fi
;;
REDIRECT)
[ -n "$excludedest" ] && fatal_error "Invalid DEST for this ACTION; rule \"$rule\""
2005-09-19 16:43:22 +02:00
2005-08-15 19:35:45 +02:00
[ -n "$serv" ] && \
fatal_error "REDIRECT rules cannot specify a server IP; rule: \"$rule\""
servport=${servport:=$port}
natrule=Yes
;;
DNAT|SAME)
[ -n "$excludedest" ] && fatal_error "Invalid DEST for this ACTION; rule \"$rule\""
2003-02-23 15:10:37 +01:00
2005-08-15 19:35:45 +02:00
[ -n "$serv" ] || \
fatal_error "$logtarget rules require a server address; rule: \"$rule\""
natrule=Yes
;;
LOG)
[ -z "$loglevel" ] && \
fatal_error "LOG requires log level"
;;
esac
2005-08-26 21:55:05 +02:00
case $SECTION in
2005-08-31 22:48:22 +02:00
ESTABLISHED|RELATED)
state="-m state --state $SECTION"
2005-08-26 21:55:05 +02:00
;;
2005-08-31 22:48:22 +02:00
*)
state=
2005-08-26 21:55:05 +02:00
;;
esac
2005-08-15 19:35:45 +02:00
if [ -n "${serv}${servport}" ]; then
if [ $COMMAND != check ]; then
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
# A specific server or server port given
2002-05-01 01:13:15 +02:00
2005-08-15 19:35:45 +02:00
if [ -n "$natrule" ]; then
add_nat_rule
[ $policy = ACCEPT ] && return
elif [ -n "$servport" -a "$servport" != "$port" ]; then
fatal_error "Only DNAT, SAME and REDIRECT rules may specify destination port mapping; rule \"$rule\""
fi
2002-05-01 01:13:15 +02:00
2005-08-15 20:33:51 +02:00
if [ -n "${excludesource}${excludedest}" ]; then
handle_exclusion
fi
2005-08-15 19:35:45 +02:00
if [ -z "$dnat_only" ]; then
if [ -n "$serv" ]; then
for serv1 in $(separate_list $serv); do
for srv in $(firewall_ip_range $serv1); do
if [ -n "$addr" -a -n "$CONNTRACK_MATCH" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A -m conntrack --ctorigdst $adr \
2005-08-26 21:55:05 +02:00
$user $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) $state
2005-08-15 19:35:45 +02:00
fi
2003-03-24 22:56:31 +01:00
2005-08-26 21:55:05 +02:00
run_iptables2 -A $chain $state $proto $ratelimit $multiport $cli $sports \
2005-08-15 22:16:34 +02:00
$(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $user -j $target
2005-08-15 19:35:45 +02:00
done
else
2003-07-01 22:29:01 +02:00
if [ -n "$loglevel" -a -z "$natrule" ]; then
2005-08-15 22:16:34 +02:00
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \
2005-10-02 18:22:52 +02:00
$state $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
2003-07-01 22:29:01 +02:00
fi
2005-08-15 19:35:45 +02:00
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
2005-08-15 22:16:34 +02:00
$cli $sports $(dest_ip_range $srv) $dports $ratelimit $user -j RETURN
2005-08-15 19:35:45 +02:00
fi
if [ "$logtarget" != NONAT ]; then
2005-08-26 21:55:05 +02:00
run_iptables2 -A $chain $state $proto $multiport $cli $sports \
2005-08-15 22:16:34 +02:00
$(dest_ip_range $srv) $dports $ratelimit $user -j $target
2005-08-15 19:35:45 +02:00
fi
2005-07-09 07:55:29 +02:00
fi
2005-08-15 19:35:45 +02:00
done
2003-07-01 22:29:01 +02:00
done
2005-08-15 19:35:45 +02:00
else
if [ -n "$loglevel" -a -z "$natrule" ]; then
2005-08-15 22:16:34 +02:00
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \
2005-10-02 18:22:52 +02:00
$state $(fix_bang $proto $sports $multiport $cli $dports)
2005-08-15 19:35:45 +02:00
fi
2003-06-02 21:26:56 +02:00
2005-08-15 19:35:45 +02:00
[ -n "$nonat" ] && \
addnatrule $(dnat_chain $source) $proto $multiport \
2005-08-15 22:16:34 +02:00
$cli $sports $dports $ratelimit $user -j RETURN
2005-07-09 06:45:32 +02:00
2005-08-15 19:35:45 +02:00
[ "$logtarget" != NONAT ] && \
2005-10-02 18:22:52 +02:00
run_iptables2 -A $chain $state $proto $multiport $cli $sports \
2005-08-15 22:16:34 +02:00
$dports $ratelimit $user -j $target
2005-08-15 19:35:45 +02:00
fi
2003-06-23 00:56:25 +02:00
fi
2003-02-27 23:28:06 +01:00
fi
2005-08-15 19:35:45 +02:00
else
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
# Destination is a simple zone
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
if [ $COMMAND != check ]; then
2005-08-15 20:33:51 +02:00
if [ -n "${excludesource}${excludedest}" ]; then
handle_exclusion
fi
2005-08-15 19:35:45 +02:00
if [ -n "$addr" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" ]; then
2005-08-15 22:16:34 +02:00
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \
2005-10-02 18:22:52 +02:00
$state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr)
2005-08-15 19:35:45 +02:00
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
2005-08-15 22:16:34 +02:00
$cli $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j RETURN
2005-08-15 19:35:45 +02:00
fi
if [ "$logtarget" != NONAT ]; then
2005-08-26 21:55:05 +02:00
run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \
2005-08-15 22:16:34 +02:00
$sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j $target
2005-08-15 19:35:45 +02:00
fi
fi
done
else
2005-07-09 07:55:29 +02:00
if [ -n "$loglevel" ]; then
2005-08-15 22:16:34 +02:00
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \
2005-10-02 18:22:52 +02:00
$state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports)
2005-07-09 07:55:29 +02:00
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
2005-08-15 22:16:34 +02:00
$cli $sports $dports $ratelimit $user -j RETURN
2005-07-09 07:55:29 +02:00
fi
2005-08-15 19:35:45 +02:00
2005-07-09 07:55:29 +02:00
if [ "$logtarget" != NONAT ]; then
2005-08-26 21:55:05 +02:00
run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \
2005-08-15 22:16:34 +02:00
$sports $dports $ratelimit $user -j $target
2005-07-09 07:55:29 +02:00
fi
fi
fi
2003-02-27 23:28:06 +01:00
fi
2003-02-08 21:58:44 +01:00
fi
2005-08-15 19:35:45 +02:00
}
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
# # # # # F u n c t i o n B o d y # # # # #
2003-08-13 19:07:05 +02:00
2004-01-27 22:16:07 +01:00
[ "x$ratelimit" = "x-" ] && ratelimit=
2003-08-15 17:54:13 +02:00
if [ -n "$ratelimit" ]; then
2003-08-13 23:31:02 +02:00
case $ratelimit in
*:*)
ratelimit="-m limit --limit ${ratelimit%:*} --limit-burst ${ratelimit#*:}"
;;
*)
ratelimit="-m limit --limit $ratelimit"
;;
esac
2003-08-13 19:07:05 +02:00
fi
# Isolate log level
2003-02-23 15:10:37 +01:00
2002-11-13 01:57:48 +01:00
if [ "$target" = "${target%:*}" ]; then
2002-05-01 01:13:15 +02:00
loglevel=
else
loglevel="${target#*:}"
2005-07-09 06:45:32 +02:00
target="${target%%:*}"
2002-05-01 01:13:15 +02:00
expandv loglevel
2005-07-09 06:45:32 +02:00
if [ "$loglevel" != "${loglevel%:*}" ]; then
logtag="${loglevel#*:}"
loglevel="${loglevel%:*}"
expandv logtag
fi
2005-07-09 07:45:05 +02:00
2005-07-09 08:13:05 +02:00
case $loglevel in
none*)
loglevel=
[ $target = LOG ] && return
;;
esac
2005-07-09 07:45:05 +02:00
2005-09-19 16:43:22 +02:00
loglevel=${loglevel%\!}
2002-05-01 01:13:15 +02:00
fi
2005-07-09 06:45:32 +02:00
#
# Save the original target in 'logtarget' for logging rules
#
logtarget=${target%-}
#
# Targets ending in "-" only apply to the nat table
#
[ $target = $logtarget ] && dnat_only= || dnat_only=Yes
2002-06-19 23:51:36 +02:00
2003-06-01 20:14:57 +02:00
# Tranform the rule:
#
2005-07-09 06:45:32 +02:00
# - parse the user specification
2003-06-01 20:14:57 +02:00
# - set 'target' to the filter table target.
# - make $FW the destination for REDIRECT
# - remove '-' suffix from logtargets while setting 'dnat_only'
# - clear 'address' if it has been set to '-'
2002-06-19 23:51:36 +02:00
2005-07-09 06:45:32 +02:00
[ "x$userspec" = x- ] && userspec=
2003-01-06 15:12:59 +01:00
[ "x$address" = "x-" ] && address=
2005-07-09 06:45:32 +02:00
if [ -n "$userspec" ]; then
2005-07-09 07:55:29 +02:00
userandgroup="-m owner"
2005-09-19 16:17:29 +02:00
2005-07-09 07:55:29 +02:00
case "$userspec" in
!*+*)
if [ -n "${userspec#*+}" ]; then
userandgroup="$userandgroup ! --cmd-owner ${userspec#*+}"
fi
userspec=${userspec%+*}
2005-09-19 16:43:22 +02:00
;;
2005-07-09 07:55:29 +02:00
*+*)
if [ -n "${userspec#*+}" ]; then
userandgroup="$userandgroup --cmd-owner ${userspec#*+}"
fi
userspec=${userspec%+*}
;;
esac
2005-07-09 06:45:32 +02:00
case "$userspec" in
!*:*)
if [ "$userspec" != "!:" ]; then
temp="${userspec#!}"
temp="${temp%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && userandgroup="$userandgroup ! --uid-owner $temp"
2005-07-09 06:45:32 +02:00
temp="${userspec#*:}"
[ -n "$temp" ] && userandgroup="$userandgroup ! --gid-owner $temp"
fi
;;
2003-09-19 21:42:05 +02:00
*:*)
2005-07-09 06:45:32 +02:00
if [ "$userspec" != ":" ]; then
temp="${userspec%:*}"
2005-08-02 18:46:30 +02:00
[ -n "$temp" ] && userandgroup="$userandgroup --uid-owner $temp"
2005-07-09 06:45:32 +02:00
temp="${userspec#*:}"
2003-09-19 21:42:05 +02:00
[ -n "$temp" ] && userandgroup="$userandgroup --gid-owner $temp"
2005-08-02 18:46:30 +02:00
fi
2003-08-21 15:18:51 +02:00
;;
2005-07-09 06:45:32 +02:00
!*)
2005-07-09 07:55:29 +02:00
[ "$userspec" != "!" ] && userandgroup="$userandgroup ! --uid-owner ${userspec#!}"
2003-08-21 15:18:51 +02:00
;;
*)
2005-07-09 07:55:29 +02:00
[ -n "$userspec" ] && userandgroup="$userandgroup --uid-owner $userspec"
2003-08-21 15:18:51 +02:00
;;
esac
2005-07-09 07:55:29 +02:00
[ "$userandgroup" = "-m owner" ] && userandgroup=
2003-08-21 15:18:51 +02:00
fi
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
case $target in
ACCEPT+|NONAT)
2005-08-26 21:55:05 +02:00
[ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION"
2005-07-09 06:45:32 +02:00
nonat=Yes
target=ACCEPT
;;
ACCEPT|LOG)
;;
DROP)
[ -n "$ratelimit" ] && fatal_error "Rate Limiting not available with DROP"
;;
REJECT)
target=reject
;;
CONTINUE)
target=RETURN
;;
2005-07-09 07:45:05 +02:00
DNAT*|SAME*)
2005-08-26 21:55:05 +02:00
[ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION"
2005-07-09 06:45:32 +02:00
target=ACCEPT
address=${address:=detect}
;;
REDIRECT*)
2005-08-26 21:55:05 +02:00
[ $SECTION = NEW ] || fatal_error "REDIRECT rules are not allowed in the $SECTION SECTION"
2005-07-09 06:45:32 +02:00
target=ACCEPT
address=${address:=all}
if [ "x-" = "x$servers" ]; then
servers=$FW
else
servers="$FW::$servers"
fi
;;
2005-08-26 21:55:05 +02:00
*-)
[ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION"
;;
2005-07-09 06:45:32 +02:00
esac
2002-06-19 23:51:36 +02:00
# Parse and validate source
2002-05-01 01:13:15 +02:00
if [ "$clients" = "${clients%:*}" ]; then
clientzone="$clients"
clients=
else
2002-09-19 01:38:09 +02:00
clientzone="${clients%%:*}"
2002-07-06 00:24:40 +02:00
clients="${clients#*:}"
2002-07-18 15:43:51 +02:00
[ -z "$clientzone" -o -z "$clients" ] && \
2003-02-08 21:58:44 +01:00
fatal_error "Empty source zone or qualifier: rule \"$rule\""
2002-05-01 01:13:15 +02:00
fi
2003-02-23 15:10:37 +01:00
2005-08-15 19:35:45 +02:00
excludesource=
case $clients in
2005-08-16 02:11:08 +02:00
*!*!*)
fatal_error "Invalid SOURCE in rule \"$rule\""
;;
2005-08-15 19:35:45 +02:00
!*)
if [ $(list_count $clients) -gt 1 ]; then
excludesource=${clients#!}
clients=
fi
;;
2005-08-16 02:11:08 +02:00
*!*)
excludesource=${clients#*!}
clients=${clients%!*}
;;
2005-08-15 19:35:45 +02:00
esac
2005-09-17 06:05:57 +02:00
2005-08-16 18:31:55 +02:00
if [ "$clientzone" = "${clientzone%!*}" ]; then
excludezones=
else
excludezones="${clientzone#*!}"
2005-09-19 16:17:29 +02:00
clientzone="${clientzone%!*}"
2005-09-19 16:43:22 +02:00
2005-08-16 18:31:55 +02:00
case $logtarget in
DNAT|REDIRECT|SAME)
;;
*)
fatal_error "Exclude zone only allowed with DNAT, SAME or REDIRECT"
;;
esac
fi
2005-09-19 16:17:29 +02:00
2003-06-01 20:14:57 +02:00
validate_zone $clientzone || fatal_error "Undefined Client Zone in rule \"$rule\""
2002-05-01 01:13:15 +02:00
2002-06-19 23:51:36 +02:00
# Parse and validate destination
2002-05-01 01:13:15 +02:00
source=$clientzone
2003-08-21 15:18:51 +02:00
if [ $source = $FW ]; then
2003-12-16 22:52:37 +01:00
source_hosts=
2005-07-09 06:45:32 +02:00
elif [ -n "$userspec" ]; then
fatal_error "Invalid use of a user-qualification: rule \"$rule\""
2003-12-16 22:52:37 +01:00
else
eval source_hosts=\"\$${source}_hosts\"
2003-08-21 15:18:51 +02:00
fi
2002-05-01 01:13:15 +02:00
if [ "$servers" = "${servers%:*}" ] ; then
serverzone="$servers"
servers=
serverport=
else
serverzone="${servers%%:*}"
servers="${servers#*:}"
if [ "$servers" != "${servers%:*}" ] ; then
serverport="${servers#*:}"
servers="${servers%:*}"
2002-07-18 15:43:51 +02:00
[ -z "$serverzone" -o -z "$serverport" ] && \
2003-02-08 21:58:44 +01:00
fatal_error "Empty destination zone or server port: rule \"$rule\""
2005-07-26 01:08:09 +02:00
if [ $(list_count $servers) -gt 1 ]; then
case $servers in
!*)
fatal_error "Exclude lists not supported in the DEST column"
;;
esac
fi
2002-05-01 01:13:15 +02:00
else
serverport=
2002-07-18 15:43:51 +02:00
[ -z "$serverzone" -o -z "$servers" ] && \
2003-03-21 05:14:20 +01:00
fatal_error "Empty destination zone or qualifier: rule \"$rule\""
2002-05-01 01:13:15 +02:00
fi
fi
2002-06-19 23:51:36 +02:00
2005-08-15 19:35:45 +02:00
excludedest=
case $servers in
2005-08-16 02:11:08 +02:00
*!*!*)
fatal_error "Invalid DEST in rule \"$rule\""
;;
2005-08-15 19:35:45 +02:00
!*)
if [ $(list_count $servers) -gt 1 ]; then
excludedest=${servers#*!}
servers=
fi
;;
2005-08-16 02:11:08 +02:00
*!*)
excludedest=${servers#*!}
servers=${servers%!*}
;;
2005-08-15 19:35:45 +02:00
esac
2005-09-19 16:17:29 +02:00
2002-05-01 01:13:15 +02:00
if ! validate_zone $serverzone; then
2003-02-08 21:58:44 +01:00
fatal_error "Undefined Server Zone in rule \"$rule\""
2002-05-01 01:13:15 +02:00
fi
dest=$serverzone
2002-06-19 23:51:36 +02:00
2003-06-01 20:14:57 +02:00
# Ensure that this rule doesn't apply to a NONE policy pair of zones
2002-06-19 23:51:36 +02:00
2002-05-01 01:13:15 +02:00
chain=${source}2${dest}
2005-08-15 22:49:06 +02:00
# If we have one or more exclusion lists, we will create a new chain and
2005-09-19 16:43:22 +02:00
# store it's name in 'chain'. We still want log rules to reflect the
2005-08-15 22:49:06 +02:00
# canonical chain so we store it's name in $logchain.
2005-08-06 18:58:18 +02:00
logchain=$chain
2002-11-11 18:38:40 +01:00
2003-03-21 20:23:03 +01:00
eval policy=\$${chain}_policy
2003-03-21 05:14:20 +01:00
2003-09-26 23:34:16 +02:00
[ -z "$policy" ] && \
fatal_error "No policy defined from zone $source to zone $dest"
2003-03-21 05:14:20 +01:00
[ $policy = NONE ] && \
fatal_error "Rules may not override a NONE policy: rule \"$rule\""
2005-08-15 19:35:45 +02:00
[ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all}
2005-08-02 18:46:30 +02:00
2005-08-15 20:33:51 +02:00
[ $COMMAND = check ] || ensurechain $chain
2003-06-01 20:14:57 +02:00
2002-06-19 23:51:36 +02:00
# Generate Netfilter rule(s)
2005-09-17 05:49:24 +02:00
2003-07-01 22:29:01 +02:00
case $logtarget in
2005-07-09 07:45:05 +02:00
DNAT*|SAME)
2005-08-15 19:35:45 +02:00
2005-07-09 07:45:05 +02:00
if [ -n "$XMULTIPORT" ] && \
! list_search $protocol "icmp" "ICMP" "1" && \
[ $(( $(list_count $ports) + $(list_count1 $(split $ports ) ) )) -le 16 -a \
$(( $(list_count $cports) + $(list_count1 $(split $cports ) ) )) -le 16 ]
then
#
# Extended MULTIPORT is enabled, and less than
# 16 ports are listed (port ranges count as two ports) - use multiport match.
#
multioption="-m multiport"
for client in $(separate_list ${clients:=-}); do
#
# add_a_rule() modifies these so we must set their values each time
#
server=${servers:=-}
port=${ports:=-}
cport=${cports:=-}
2005-08-15 22:49:06 +02:00
add_a_rule
2005-07-09 07:45:05 +02:00
done
elif [ -n "$MULTIPORT" ] && \
2003-10-08 20:45:26 +02:00
! list_search $protocol "icmp" "ICMP" "1" && \
[ "$ports" = "${ports%:*}" -a \
2003-07-01 22:29:01 +02:00
"$cports" = "${cports%:*}" -a \
2005-07-09 06:45:32 +02:00
$(list_count $ports) -le 15 -a \
$(list_count $cports) -le 15 ]
2003-07-01 22:29:01 +02:00
then
#
# MULTIPORT is enabled, there are no port ranges in the rule and less than
# 16 ports are listed - use multiport match.
#
multioption="-m multiport"
2005-07-09 06:45:32 +02:00
for client in $(separate_list ${clients:=-}); do
2003-07-01 22:29:01 +02:00
#
# add_a_rule() modifies these so we must set their values each time
#
server=${servers:=-}
port=${ports:=-}
cport=${cports:=-}
2005-08-15 22:49:06 +02:00
add_a_rule
2003-07-01 22:29:01 +02:00
done
else
#
# MULTIPORT is disabled or the rule isn't compatible with multiport match
#
multioption=
2005-07-09 06:45:32 +02:00
for client in $(separate_list ${clients:=-}); do
for port in $(separate_list ${ports:=-}); do
for cport in $(separate_list ${cports:=-}); do
2003-07-01 22:29:01 +02:00
server=${servers:=-}
2005-08-15 22:49:06 +02:00
add_a_rule
2003-07-01 22:29:01 +02:00
done
done
done
fi
;;
*)
2005-07-09 07:45:05 +02:00
if [ -n "$XMULTIPORT" ] && \
! list_search $protocol "icmp" "ICMP" "1" && \
[ $(( $(list_count $ports) + $(list_count1 $(split $ports ) ) )) -le 16 -a \
$(( $(list_count $cports) + $(list_count1 $(split $cports ) ) )) -le 16 ]
then
#
# Extended MULTIPORT is enabled, and less than
# 16 ports are listed (port ranges count as two ports) - use multiport match.
#
multioption="-m multiport"
for client in $(separate_list ${clients:=-}); do
for server in $(separate_list ${servers:=-}); do
#
# add_a_rule() modifies these so we must set their values each time
#
port=${ports:=-}
cport=${cports:=-}
2005-08-15 22:49:06 +02:00
add_a_rule
2005-07-09 07:45:05 +02:00
done
done
elif [ -n "$MULTIPORT" ] && \
2003-10-08 20:45:26 +02:00
! list_search $protocol "icmp" "ICMP" "1" && \
[ "$ports" = "${ports%:*}" -a \
2003-07-01 22:29:01 +02:00
"$cports" = "${cports%:*}" -a \
2005-07-09 06:45:32 +02:00
$(list_count $ports) -le 15 -a \
$(list_count $cports) -le 15 ]
2003-07-01 22:29:01 +02:00
then
#
# MULTIPORT is enabled, there are no port ranges in the rule and less than
# 16 ports are listed - use multiport match.
#
multioption="-m multiport"
2005-07-09 06:45:32 +02:00
for client in $(separate_list ${clients:=-}); do
for server in $(separate_list ${servers:=-}); do
2003-07-01 22:29:01 +02:00
#
# add_a_rule() modifies these so we must set their values each time
#
port=${ports:=-}
cport=${cports:=-}
2005-08-15 22:49:06 +02:00
add_a_rule
2002-06-02 19:05:51 +02:00
done
2002-05-01 01:13:15 +02:00
done
2003-07-01 22:29:01 +02:00
else
#
# MULTIPORT is disabled or the rule isn't compatible with multiport match
#
multioption=
2005-07-09 06:45:32 +02:00
for client in $(separate_list ${clients:=-}); do
for server in $(separate_list ${servers:=-}); do
for port in $(separate_list ${ports:=-}); do
for cport in $(separate_list ${cports:=-}); do
2005-08-15 22:49:06 +02:00
add_a_rule
2003-07-01 22:29:01 +02:00
done
done
done
done
fi
;;
esac
2003-06-01 20:14:57 +02:00
#
# Report Result
#
2005-07-09 06:45:32 +02:00
if [ $COMMAND = check ]; then
progress_message " Rule \"$rule\" checked."
2003-02-27 23:28:06 +01:00
else
2005-07-09 06:45:32 +02:00
progress_message " Rule \"$rule\" added."
2003-02-27 23:28:06 +01:00
fi
2002-05-01 01:13:15 +02:00
}
2005-07-26 01:08:09 +02:00
#
# Process a macro invocation in the rules file
#
process_macro() # $1 = target
# $2 = param
# $2 = clients
# $3 = servers
# $4 = protocol
# $5 = ports
# $6 = cports
# $7 = address
# $8 = ratelimit
# $9 = userspec
{
local itarget="$1"
local param="$2"
local iclients="$3"
local iservers="$4"
local iprotocol="$5"
local iports="$6"
local icports="$7"
local iaddress="$8"
local iratelimit="$9"
local iuserspec="${10}"
progress_message "..Expanding Macro $(find_file macro.${itarget%%:*})..."
while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do
expandv mtarget mclients mservers mprotocol mports mcports mratelimit muserspec
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
mtarget=$(merge_levels $itarget $mtarget)
case $mtarget in
PARAM|PARAM:*)
[ -n "$param" ] && mtarget=$(substitute_action $param $mtarget) || fatal_error "PARAM requires that a parameter be supplied in macro invocation"
;;
2005-08-30 00:51:49 +02:00
esac
2005-08-31 00:35:19 +02:00
case ${mtarget%%:*} in
2005-08-30 00:51:49 +02:00
ACCEPT|ACCEPT+|NONAT|DROP|REJECT|DNAT|DNAT-|REDIRECT|REDIRECT-|LOG|CONTINUE|QUEUE|SAME|SAME-)
;;
*)
if list_search ${mtarget%%:*} $ACTIONS; then
if ! list_search $mtarget $USEDACTIONS; then
createactionchain $mtarget
USEDACTIONS="$USEDACTIONS $mtarget"
fi
2005-09-19 16:17:29 +02:00
2005-08-30 00:51:49 +02:00
mtarget=$(find_logactionchain $mtarget)
else
fatal_error "Invalid Action in rule \"$mtarget ${mclients:--} ${mservers:--} ${mprotocol:--} ${mports:--} ${mcports:--} ${xaddress:--} ${mratelimit:--} ${muserspec:--}\""
fi
;;
esac
2005-07-26 01:08:09 +02:00
if [ -n "$mclients" ]; then
case $mclients in
-)
mclients=${iclients}
;;
*)
mclients=${mclients}:${iclients}
;;
esac
else
mclients=${iclients}
fi
if [ -n "$mservers" ]; then
case $mservers in
-)
mservers=${iservers}
;;
*)
mservers=${mservers}:${iservers}
;;
esac
else
2005-08-30 00:51:49 +02:00
mservers=${iservers}
2005-07-26 01:08:09 +02:00
fi
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
[ -n "$iprotocol" ] && [ "x${iprotocol}" != x- ] && mprotocol=$iprotocol
[ -n "$iports" ] && [ "x${iports}" != x- ] && mports=$iports
[ -n "$icports" ] && [ "x${icports}" != x- ] && mcports=$icports
[ -n "$iratelimit" ] && [ "x${iratelimit}" != x- ] && mratelimit=$iratelimit
[ -n "$iuserspec" ] && [ "x${iuserspec}" != x- ] && muserspec=$iuserspec
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
rule="$mtarget ${mclients=-} ${mservers:=-} ${mprotocol:=-} ${mports:=-} ${mcports:=-} ${xaddress:=-} ${mratelimit:=-} ${muserspec:=-}"
process_rule $mtarget $mclients $mservers $mprotocol $mports $mcports ${iaddress:=-} $mratelimit $muserspec
done < $TMP_DIR/macro.${itarget%%:*}
2005-08-02 18:46:30 +02:00
2005-07-26 01:08:09 +02:00
progress_message "..End Macro"
}
2002-10-23 18:48:40 +02:00
#
2003-02-27 23:28:06 +01:00
# Process the rules file for the 'start', 'restart' or 'check' command.
2002-10-23 18:48:40 +02:00
#
2005-08-30 00:17:00 +02:00
process_rules()
2002-05-01 01:13:15 +02:00
{
2002-11-13 01:57:48 +01:00
#
# Process a rule where the source or destination is "all"
#
2005-09-19 16:43:22 +02:00
process_wildcard_rule() # $1 = Yes, if this is a macro, $2 = Yes if we want intrazone traffic
2005-08-04 22:24:23 +02:00
{
2003-12-04 03:01:08 +01:00
local yclients yservers ysourcezone ydestzone ypolicy
2005-09-19 16:43:22 +02:00
2002-11-11 20:21:47 +01:00
for yclients in $xclients; do
for yservers in $xservers; do
2003-12-04 03:01:08 +01:00
ysourcezone=${yclients%%:*}
ydestzone=${yservers%%:*}
2005-09-27 16:30:11 +02:00
if [ "${ysourcezone}" != "${ydestzone}" -o "$2" = Yes ] ; then
2003-12-04 03:01:08 +01:00
eval ypolicy=\$${ysourcezone}2${ydestzone}_policy
if [ "$ypolicy" != NONE ] ; then
2005-07-26 01:08:09 +02:00
if [ "$1" = Yes ]; then
process_macro $xtarget "$xparam" $yclients $yservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec
else
rule="$xtarget $yclients $yservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec"
process_rule $xtarget $yclients $yservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec
fi
2003-12-04 03:01:08 +01:00
fi
2002-11-11 20:21:47 +01:00
fi
done
done
}
2005-07-26 01:08:09 +02:00
do_it() # $1 = "Yes" if the target is a macro.
2005-08-02 18:46:30 +02:00
{
2005-08-04 22:24:23 +02:00
expandv xprotocol xports xcports xaddress xratelimit xuserspec intrazone=
2005-08-27 16:39:43 +02:00
if [ -z "$SECTIONS" ]; then
finish_section ESTABLISHED,RELATED
SECTIONS="ESTABLISHED RELATED NEW"
SECTION=NEW
fi
2005-08-26 21:55:05 +02:00
2005-09-19 16:43:22 +02:00
case $xclients in
2005-08-04 22:24:23 +02:00
all+)
xclients=all
intrazone=Yes
;;
esac
case $xservers in
all+)
xservers=all
intrazone=Yes
;;
esac
2003-12-04 03:01:08 +01:00
if [ "x$xclients" = xall ]; then
2005-07-26 01:08:09 +02:00
xclients="$ZONES $FW"
2003-12-04 03:01:08 +01:00
if [ "x$xservers" = xall ]; then
2005-07-26 01:08:09 +02:00
xservers="$ZONES $FW"
2003-12-04 03:01:08 +01:00
fi
2005-08-04 22:24:23 +02:00
process_wildcard_rule "$1" $intrazone
2005-07-09 07:45:05 +02:00
return
2003-12-04 03:01:08 +01:00
fi
if [ "x$xservers" = xall ]; then
2005-07-26 01:08:09 +02:00
xservers="$ZONES $FW"
2005-08-04 22:24:23 +02:00
process_wildcard_rule "$1" $intrazone
2005-07-09 07:45:05 +02:00
return
2003-12-04 03:01:08 +01:00
fi
2005-07-26 01:08:09 +02:00
if [ "$1" = Yes ]; then
process_macro $xtarget "$xparam" $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec
else
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec"
process_rule $xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec
fi
2003-12-04 03:01:08 +01:00
}
2005-07-09 06:45:32 +02:00
while read xtarget xclients xservers xprotocol xports xcports xaddress xratelimit xuserspec; do
2005-07-09 07:45:05 +02:00
expandv xtarget xclients xservers
if [ "x$xclients" = xnone -o "x$servers" = xnone ]; then
2005-07-26 01:08:09 +02:00
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec"
2005-07-09 07:45:05 +02:00
progress_message " Rule \"$rule\" ignored."
continue
fi
case "${xtarget%%:*}" in
ACCEPT|ACCEPT+|NONAT|DROP|REJECT|DNAT|DNAT-|REDIRECT|REDIRECT-|LOG|CONTINUE|QUEUE|SAME|SAME-)
2005-07-26 01:08:09 +02:00
do_it No
2002-11-11 20:21:47 +01:00
;;
2005-08-26 21:55:05 +02:00
SECTION)
list_search $xclients $SECTIONS && fatal_error "Duplicate or out of order SECTION $xclients"
case $xclients in
ESTABLISHED)
SECTIONS=ESTABLISHED
;;
RELATED)
finish_section ESTABLISHED
SECTIONS="ESTABLISHED RELATED"
;;
NEW)
[ $SECTION = RELATED ] && finish_section RELATED || finish_section ESTABLISHED,RELATED
SECTIONS="ESTABLISHED RELATED NEW"
;;
*)
fatal_error "Invalid SECTION $xclients"
;;
esac
[ -n "$xservers" ] && fatal_error "Invalid SECTION $xclients $xservers"
SECTION=$xclients
;;
2002-11-11 20:21:47 +01:00
*)
2005-07-09 07:45:05 +02:00
if list_search ${xtarget%%:*} $ACTIONS; then
if ! list_search $xtarget $USEDACTIONS; then
createactionchain $xtarget
USEDACTIONS="$USEDACTIONS $xtarget"
2005-07-09 06:45:32 +02:00
fi
2005-07-09 07:45:05 +02:00
xtarget=$(find_logactionchain $xtarget)
2005-08-02 18:46:30 +02:00
do_it No
2003-12-04 03:01:08 +01:00
else
2005-07-26 01:08:09 +02:00
xtarget1=$(map_old_action ${xtarget%%:*})
2005-08-02 18:46:30 +02:00
case $xtarget1 in
2005-07-26 01:08:09 +02:00
*/*)
xparam=${xtarget1#*/}
xtarget1=${xtarget1%%/*}
xtarget=$(substitute_action $xtarget1 $xtarget)
;;
*)
xparam=
;;
esac
f=macro.$xtarget1
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
if [ -f $TMP_DIR/$f ]; then
do_it Yes
else
fn=$(find_file $f)
if [ -f $fn ]; then
strip_file $f $fn
do_it Yes
else
rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec"
fatal_error "Invalid Action in rule \"$rule\""
fi
fi
2003-12-04 03:01:08 +01:00
fi
2002-11-11 20:21:47 +01:00
;;
2003-02-23 15:10:37 +01:00
2002-05-01 01:13:15 +02:00
esac
done < $TMP_DIR/rules
2005-08-26 21:55:05 +02:00
case $SECTION in
ESTABLISHED)
finish_section ESTABLISHED,RELATED
;;
RELATED)
finish_section RELATED
;;
esac
2005-08-27 00:23:56 +02:00
SECTION=DONE
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Process a record from the tos file
#
# The caller has loaded the column contents from the record into the following
# variables:
#
# src dst protocol sport dport tos
#
# and has loaded a space-separated list of their values in "rule".
#
2002-05-01 01:13:15 +02:00
process_tos_rule() {
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# Parse the contents of the 'src' variable
#
if [ "$src" = "${src%:*}" ]; then
srczone="$src"
src=
else
srczone="${src%:*}"
src="${src#*:}"
fi
source=
#
# Validate the source zone
#
if validate_zone $srczone; then
source=$srczone
elif [ "$srczone" = "all" ]; then
source="all"
else
2005-07-26 01:08:09 +02:00
error_message "WARNING: Undefined Source Zone - rule \"$rule\" ignored"
2002-05-01 01:13:15 +02:00
return
fi
[ -n "$src" ] && case "$src" in
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
2002-05-01 01:13:15 +02:00
#
2005-07-09 06:45:32 +02:00
# IP Address or networks
2002-05-01 01:13:15 +02:00
#
2005-07-09 07:45:05 +02:00
src="$(source_ip_range $src)"
2002-05-01 01:13:15 +02:00
;;
2002-07-06 00:24:40 +02:00
~*)
2005-07-09 06:45:32 +02:00
src=$(mac_match $src)
2002-05-01 01:13:15 +02:00
;;
*)
#
# Assume that this is a device name
#
2005-07-09 06:45:32 +02:00
if ! verify_interface $src ; then
2005-07-26 01:08:09 +02:00
error_message "WARNING: Unknown Interface in rule \"$rule\" ignored"
2005-07-09 06:45:32 +02:00
return
fi
src="$(match_source_dev $src)"
2002-05-01 01:13:15 +02:00
;;
esac
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# Parse the contents of the 'dst' variable
#
if [ "$dst" = "${dst%:*}" ]; then
dstzone="$dst"
dst=
else
dstzone="${dst%:*}"
dst="${dst#*:}"
fi
dest=
#
# Validate the destination zone
#
if validate_zone $dstzone; then
dest=$dstzone
elif [ "$dstzone" = "all" ]; then
dest="all"
else
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Undefined Destination Zone - rule \"$rule\" ignored"
2002-05-01 01:13:15 +02:00
return
fi
[ -n "$dst" ] && case "$dst" in
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
2002-05-01 01:13:15 +02:00
#
2005-07-09 06:45:32 +02:00
# IP Address or networks
2002-05-01 01:13:15 +02:00
#
;;
*)
#
# Assume that this is a device name
#
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Invalid Destination - rule \"$rule\" ignored"
2002-05-01 01:13:15 +02:00
return
;;
esac
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# Setup PROTOCOL and PORT variables
#
sports=""
dports=""
case $protocol in
tcp|udp|TCP|UDP|6|17)
[ -n "$sport" ] && [ "x${sport}" != "x-" ] && \
sports="--sport $sport"
[ -n "$dport" ] && [ "x${dport}" != "x-" ] && \
dports="--dport $dport"
;;
icmp|ICMP|0)
[ -n "$dport" ] && [ "x${dport}" != "x-" ] && \
dports="--icmp-type $dport"
;;
all|ALL)
protocol=
;;
*)
;;
esac
protocol="${protocol:+-p $protocol}"
tos="-j TOS --set-tos $tos"
case "$dstzone" in
all|ALL)
dst=0.0.0.0/0
;;
*)
[ -z "$dst" ] && eval dst=\$${dstzone}_hosts
;;
esac
for dest in $dst; do
2005-07-09 07:45:05 +02:00
dest="$(dest_ip_range $dest)"
2002-05-01 01:13:15 +02:00
case $srczone in
$FW)
2002-12-18 22:26:03 +01:00
run_iptables2 -t mangle -A outtos \
2002-05-01 01:13:15 +02:00
$protocol $dest $dports $sports $tos
;;
all|ALL)
2002-12-18 22:26:03 +01:00
run_iptables2 -t mangle -A outtos \
2002-05-01 01:13:15 +02:00
$protocol $dest $dports $sports $tos
2002-12-18 22:58:21 +01:00
run_iptables2 -t mangle -A pretos \
2002-05-01 01:13:15 +02:00
$protocol $dest $dports $sports $tos
;;
*)
if [ -n "$src" ]; then
2002-12-18 22:26:03 +01:00
run_iptables2 -t mangle -A pretos $src \
2002-05-01 01:13:15 +02:00
$protocol $dest $dports $sports $tos
else
eval interfaces=\$${srczone}_interfaces
for interface in $interfaces; do
2002-12-18 22:26:03 +01:00
run_iptables2 -t mangle -A pretos -i $interface \
2002-05-01 01:13:15 +02:00
$protocol $dest $dports $sports $tos
done
fi
;;
esac
done
2005-07-09 06:45:32 +02:00
progress_message " Rule \"$rule\" added."
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Process the tos file
#
2002-05-01 01:13:15 +02:00
process_tos() # $1 = name of tos file
{
echo "Processing $1..."
strip_file tos $1
2005-07-09 07:55:29 +02:00
if [ -s $TMP_DIR/tos ] ; then
run_iptables -t mangle -N pretos
run_iptables -t mangle -N outtos
while read src dst protocol sport dport tos; do
expandv src dst protocol sport dport tos
rule="$(echo $src $dst $protocol $sport $dport $tos)"
process_tos_rule
done < $TMP_DIR/tos
2002-05-01 01:13:15 +02:00
2005-07-09 07:55:29 +02:00
run_iptables -t mangle -A PREROUTING -j pretos
run_iptables -t mangle -A OUTPUT -j outtos
fi
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Display elements of a list with leading white space
#
2002-05-01 01:13:15 +02:00
display_list() # $1 = List Title, rest of $* = list to display
{
[ $# -gt 1 ] && echo " $*"
}
policy_rules() # $1 = chain to add rules to
2002-07-06 00:24:40 +02:00
# $2 = policy
2005-08-26 19:16:09 +02:00
# $3 = loglevel
2002-05-01 01:13:15 +02:00
{
local target="$2"
case "$target" in
2005-07-09 06:45:32 +02:00
ACCEPT)
[ -n "$ACCEPT_common" ] && run_iptables -A $1 -j $ACCEPT_common
;;
DROP)
[ -n "$DROP_common" ] && run_iptables -A $1 -j $DROP_common
;;
REJECT)
2005-08-02 18:46:30 +02:00
[ -n "$REJECT_common" ] && run_iptables -A $1 -j $REJECT_common
2005-07-09 06:45:32 +02:00
target=reject
;;
2005-07-09 07:45:05 +02:00
QUEUE)
2005-08-02 18:46:30 +02:00
[ -n "$QUEUE_common" ] && run_iptables -A $1 -j $QUEUE_common
2005-07-09 07:45:05 +02:00
;;
2005-07-09 06:45:32 +02:00
CONTINUE)
target=
;;
*)
fatal_error "Invalid policy ($policy) for $1"
;;
2002-05-01 01:13:15 +02:00
esac
2005-08-26 19:16:09 +02:00
if [ $# -eq 3 -a "x${3}" != "x-" ]; then
log_rule $3 $1 $2
2002-12-13 04:23:46 +01:00
fi
2002-06-01 02:28:18 +02:00
[ -n "$target" ] && run_iptables -A $1 -j $target
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Generate default policy & log level rules for the passed client & server
# zones
#
# This function is only called when the canonical chain for this client/server
# pair is known to exist. If the default policy for this pair specifies the
# same chain then we add the policy (and logging) rule to the canonical chain;
# otherwise add a rule to the canonical chain to jump to the appropriate
# policy chain.
#
2002-05-01 01:13:15 +02:00
default_policy() # $1 = client $2 = server
{
local chain="${1}2${2}"
local policy=
local loglevel=
2002-06-02 19:05:51 +02:00
local chain1
jump_to_policy_chain() {
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# Add a jump to from the canonical chain to the policy chain. On return,
# $chain is set to the name of the policy chain
#
2002-07-06 00:24:40 +02:00
run_iptables -A $chain -j $chain1
chain=$chain1
2002-06-02 19:05:51 +02:00
}
2002-05-01 01:13:15 +02:00
2005-08-27 00:23:56 +02:00
report_syn_flood_protection()
{
progress_message " Enabled SYN flood protection"
}
2002-05-01 01:13:15 +02:00
apply_default()
{
2002-10-23 18:48:40 +02:00
#
2002-12-07 04:21:32 +01:00
# Generate policy file column values from the policy chain
2002-10-23 18:48:40 +02:00
#
2002-12-07 04:21:32 +01:00
eval policy=\$${chain1}_policy
eval loglevel=\$${chain1}_loglevel
2005-08-02 18:46:30 +02:00
eval synparams=\$${chain1}_synparams
2002-05-01 01:13:15 +02:00
#
2002-12-07 04:21:32 +01:00
# Add the appropriate rules to the canonical chain ($chain) to enforce
# the specified policy
2002-05-01 01:13:15 +02:00
2002-06-01 02:28:18 +02:00
if [ "$chain" = "$chain1" ]; then
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# The policy chain is the canonical chain; add policy rule to it
# The syn flood jump has already been added if required.
#
2005-08-26 19:16:09 +02:00
policy_rules $chain $policy $loglevel
2002-05-01 01:13:15 +02:00
else
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# The policy chain is different from the canonical chain -- approach
# depends on the policy
2002-05-01 01:13:15 +02:00
#
2002-06-02 19:05:51 +02:00
case $policy in
2005-07-09 07:45:05 +02:00
ACCEPT|QUEUE)
2002-07-06 00:24:40 +02:00
if [ -n "$synparams" ]; then
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# To avoid double-counting SYN packets, enforce the policy
# in this chain.
#
2005-08-27 00:23:56 +02:00
report_syn_flood_protection
2005-08-26 19:16:09 +02:00
policy_rules $chain $policy $loglevel
2002-06-02 19:05:51 +02:00
else
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# No problem with double-counting so just jump to the
# policy chain.
#
jump_to_policy_chain
fi
;;
CONTINUE)
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# Silly to jump to the policy chain -- add any logging
# rules and enable SYN flood protection if requested
#
[ -n "$synparams" ] && \
2005-08-27 00:23:56 +02:00
report_syn_flood_protection
2005-08-26 19:16:09 +02:00
policy_rules $chain $policy $loglevel
2002-06-02 19:05:51 +02:00
;;
*)
2002-10-23 18:48:40 +02:00
#
2002-06-02 19:05:51 +02:00
# DROP or REJECT policy -- enforce in the policy chain and
# enable SYN flood protection if requested.
#
[ -n "$synparams" ] && \
2005-08-27 00:23:56 +02:00
report_syn_flood_protection
2002-07-06 00:24:40 +02:00
jump_to_policy_chain
2002-06-02 19:05:51 +02:00
;;
esac
2002-05-01 01:13:15 +02:00
fi
2002-06-02 19:05:51 +02:00
2005-07-09 06:45:32 +02:00
progress_message " Policy $policy for $1 to $2 using chain $chain"
2002-05-01 01:13:15 +02:00
}
2002-12-07 04:21:32 +01:00
eval chain1=\$${1}2${2}_policychain
2002-05-01 01:13:15 +02:00
2002-12-07 04:21:32 +01:00
if [ -n "$chain1" ]; then
apply_default $1 $2
else
2003-02-08 21:58:44 +01:00
fatal_error "No default policy for zone $1 to zone $2"
2002-12-07 04:21:32 +01:00
fi
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# Complete a standard chain
#
# - run any supplied user exit
# - search the policy file for an applicable policy and add rules as
# appropriate
2002-07-06 00:24:40 +02:00
# - If no applicable policy is found, add rules for an assummed
2002-05-01 01:13:15 +02:00
# policy of DROP INFO
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
complete_standard_chain() # $1 = chain, $2 = source zone, $3 = destination zone
{
local policy=
local loglevel=
2002-12-07 04:21:32 +01:00
local policychain=
2002-05-01 01:13:15 +02:00
run_user_exit $1
2003-02-23 15:10:37 +01:00
2002-12-07 04:21:32 +01:00
eval policychain=\$${2}2${3}_policychain
2002-05-01 01:13:15 +02:00
2002-12-07 04:21:32 +01:00
if [ -n "$policychain" ]; then
eval policy=\$${policychain}_policy
eval loglevel=\$${policychain}_loglevel
2005-08-02 18:46:30 +02:00
eval
2002-05-01 01:13:15 +02:00
2005-09-14 23:04:07 +02:00
policy_rules $1 $policy $loglevel
2002-12-07 04:21:32 +01:00
else
2005-09-14 23:04:07 +02:00
policy_rules $1 DROP info
2002-12-07 04:21:32 +01:00
fi
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Find the appropriate chain to pass packets from a source zone to a
# destination zone
#
# If the canonical chain for this zone pair exists, echo it's name; otherwise
# locate and echo the name of the appropriate policy chain
#
2002-05-01 01:13:15 +02:00
rules_chain() # $1 = source zone, $2 = destination zone
{
2005-07-26 01:08:09 +02:00
local chain=${1}2${2} local policy
2002-05-01 01:13:15 +02:00
havechain $chain && { echo $chain; return; }
2003-02-23 15:10:37 +01:00
2003-03-21 20:47:19 +01:00
[ "$1" = "$2" ] && { echo ACCEPT; return; }
2002-12-07 04:21:32 +01:00
eval chain=\$${chain}_policychain
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
eval policy=\$${chain}_policy
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
if [ "$policy" != CONTINUE ] ; then
[ -n "$chain" ] && { echo $chain; return; }
fatal_error "No policy defined for zone $1 to zone $2"
fi
2002-05-01 01:13:15 +02:00
}
2003-01-24 23:47:22 +01:00
#
2005-07-09 06:45:32 +02:00
# echo the list of networks routed out of a given interface
2003-01-24 23:47:22 +01:00
#
2005-07-09 06:45:32 +02:00
get_routed_networks() # $1 = interface name
2003-01-24 23:47:22 +01:00
{
local address
2003-01-24 23:59:49 +01:00
local rest
2003-01-24 23:47:22 +01:00
2003-01-24 23:59:49 +01:00
ip route show dev $1 2> /dev/null |
while read address rest; do
2003-03-11 15:55:01 +01:00
if [ "x$address" = xdefault ]; then
2005-07-26 01:08:09 +02:00
error_message "WARNING: default route ignored on interface $1"
2003-03-11 15:55:01 +01:00
else
[ "$address" = "${address%/*}" ] && address="${address}/32"
echo $address
fi
2003-01-24 23:47:22 +01:00
done
}
2003-07-04 17:08:29 +02:00
2005-07-09 07:55:29 +02:00
#
# Set up Routing
#
2005-07-26 01:08:09 +02:00
setup_routes()
2005-07-09 07:55:29 +02:00
{
2005-07-26 01:08:09 +02:00
run_iptables -t mangle -A PREROUTING -m connmark ! --mark 0 -j CONNMARK --restore-mark
2005-08-01 19:17:24 +02:00
run_iptables -t mangle -A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark
2005-07-26 01:08:09 +02:00
run_iptables -t mangle -N routemark
2005-07-09 07:55:29 +02:00
2005-07-26 01:08:09 +02:00
for interface in $ROUTEMARK_INTERFACES ; do
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
iface=$(chain_base $interface)
eval mark_value=\$${iface}_routemark
2005-07-09 07:55:29 +02:00
2005-07-26 01:08:09 +02:00
run_iptables -t mangle -A PREROUTING -i $interface -m mark --mark 0 -j routemark
run_iptables -t mangle -A routemark -i $interface -j MARK --set-mark $mark_value
2005-07-09 07:55:29 +02:00
2005-07-26 01:08:09 +02:00
done
2005-07-09 07:55:29 +02:00
2005-07-26 01:08:09 +02:00
run_iptables -t mangle -A routemark -m mark ! --mark 0 -j CONNMARK --save-mark --mask 255
2005-07-09 07:55:29 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Set up Source NAT (including masquerading)
#
2002-05-01 01:13:15 +02:00
setup_masq()
{
2005-07-09 07:45:05 +02:00
do_ipsec_options() {
2005-08-02 18:46:30 +02:00
local options="$(separate_list $ipsec)" option
2005-07-09 07:45:05 +02:00
policy="-m policy --pol ipsec --dir out"
for option in $options; do
case $option in
[Yy]es) ;;
strict) policy="$policy --strict" ;;
next) policy="$policy --next" ;;
reqid=*) policy="$policy --reqid ${option#*=}" ;;
spi=*) policy="$policy --spi ${option#*=}" ;;
proto=*) policy="$policy --proto ${option#*=}" ;;
mode=*) policy="$policy --mode ${option#*=}" ;;
tunnel-src=*) policy="$policy --tunnel-src ${option#*=}" ;;
tunnel-dst=*) policy="$policy --tunnel-dst ${option#*=}" ;;
reqid!=*) policy="$policy ! --reqid ${option#*=}" ;;
spi!=*) policy="$policy ! --spi ${option#*=}" ;;
proto!=*) policy="$policy ! --proto ${option#*=}" ;;
mode!=*) policy="$policy ! --mode ${option#*=}" ;;
tunnel-src!=*) policy="$policy ! --tunnel-src ${option#*=}" ;;
tunnel-dst!=*) policy="$policy ! --tunnel-dst ${option#*=}" ;;
*) fatal_error "Invalid IPSEC option \"$option\"" ;;
esac
done
}
2002-05-01 01:13:15 +02:00
setup_one() {
2005-07-09 07:45:05 +02:00
local add_snat_aliases=$ADD_SNAT_ALIASES pre_nat= policy= destnets=
[ "x$ipsec" = x- ] && ipsec=
case $ipsec in
Yes|yes)
[ -n "$POLICY_MATCH" ] || \
fatal_error "IPSEC=Yes requires policy match support in your kernel and iptables"
policy="-m policy --pol ipsec --dir out"
;;
No|no)
[ -n "$POLICY_MATCH" ] || \
fatal_error "IPSEC=No requires policy match support in your kernel and iptables"
policy="-m policy --pol none --dir out"
;;
*)
if [ -n "$ipsec" ]; then
do_ipsec_options
elif [ -n "$POLICY_MATCH" ]; then
policy="-m policy --pol none --dir out"
fi
;;
esac
2002-05-01 01:13:15 +02:00
2003-01-25 00:43:22 +01:00
case $fullinterface in
2005-07-09 07:45:05 +02:00
+*)
pre_nat=Yes
fullinterface=${fullinterface#+}
;;
esac
case $fullinterface in
*::*)
add_snat_aliases=
destnets="${fullinterface##*:}"
fullinterface="${fullinterface%:*}"
2005-09-19 16:43:22 +02:00
;;
2003-01-25 00:43:22 +01:00
*:*:*)
2005-07-09 06:45:32 +02:00
# Both alias name and networks
2004-01-22 03:06:56 +01:00
destnets="${fullinterface##*:}"
2003-01-25 00:43:22 +01:00
fullinterface="${fullinterface%:*}"
;;
2005-07-09 07:45:05 +02:00
*:)
add_snat_aliases=
fullinterface=${fullinterface%:}
;;
2003-01-25 00:43:22 +01:00
*:*)
2005-07-09 06:45:32 +02:00
# Alias name OR networks
2003-01-25 00:43:22 +01:00
case ${fullinterface#*:} in
*.*)
2005-07-09 06:45:32 +02:00
# It's a networks
2004-01-22 03:06:56 +01:00
destnets="${fullinterface#*:}"
2003-01-25 00:43:22 +01:00
fullinterface="${fullinterface%:*}"
;;
*)
#it's an alias name
;;
esac
;;
*)
;;
esac
interface=${fullinterface%:*}
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
if ! list_search $interface $ALL_INTERFACES; then
2003-02-08 21:58:44 +01:00
fatal_error "Unknown interface $interface"
2002-09-01 19:34:59 +02:00
fi
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
if [ "$networks" = "${networks%!*}" ]; then
2002-05-01 01:13:15 +02:00
nomasq=
else
2005-07-09 06:45:32 +02:00
nomasq="${networks#*!}"
networks="${networks%!*}"
2002-05-01 01:13:15 +02:00
fi
2005-07-20 03:10:28 +02:00
source="${networks:=0.0.0.0/0}"
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
case $source in
2005-07-09 07:55:29 +02:00
*.*.*|+*|!+*)
2002-05-01 01:13:15 +02:00
;;
*)
2005-07-09 06:45:32 +02:00
networks=$(get_routed_networks $networks)
[ -z "$networks" ] && fatal_error "Unable to determine the routes through interface \"$source\""
networks="$networks"
2002-05-01 01:13:15 +02:00
;;
esac
2005-09-19 16:43:22 +02:00
[ "x$addresses" = x- ] && addresses=
2005-07-09 07:45:05 +02:00
if [ -n "$addresses" -a -n "$add_snat_aliases" ]; then
2005-07-09 06:45:32 +02:00
for address in $(separate_list $addresses); do
2005-07-09 07:45:05 +02:00
address=${address%:)}
if [ -n "$address" ]; then
for addr in $(ip_range_explicit ${address%:*}) ; do
2005-08-23 22:41:18 +02:00
if ! list_search $addr $ALIASES_TO_ADD; then
2005-08-02 18:46:30 +02:00
[ -n "$RETAIN_ALIASES" ] || save_command qt ip addr del $addr dev $interface
2005-08-23 22:41:18 +02:00
ALIASES_TO_ADD="$ALIASES_TO_ADD $addr $fullinterface"
2005-07-09 07:45:05 +02:00
case $fullinterface in
*:*)
fullinterface=${fullinterface%:*}:$((${fullinterface#*:} + 1 ))
;;
esac
fi
done
fi
2003-06-22 18:58:33 +02:00
done
2002-05-01 01:13:15 +02:00
fi
2005-07-09 06:45:32 +02:00
[ "x$proto" = x- ] && proto=
[ "x$ports" = x- ] && ports=
if [ -n "$proto" ]; then
displayproto="($proto)"
case $proto in
tcp|TCP|udp|UDP|6|17)
if [ -n "$ports" ]; then
displayproto="($proto $ports)"
listcount=$(list_count $ports)
if [ $listcount -gt 1 ]; then
case $ports in
*:*)
2005-07-09 07:45:05 +02:00
if [ -n "$XMULTIPORT" ]; then
if [ $(($listcount + $(list_count1 $(split $ports) ) )) -le 16 ]; then
ports="-m multiport --dports $ports"
else
fatal_error "More than 15 entries in port list ($ports)"
fi
else
fatal_error "Port Range not allowed in list ($ports)"
fi
2005-07-09 06:45:32 +02:00
;;
*)
if [ -n "$MULTIPORT" ]; then
2005-07-09 07:45:05 +02:00
[ $listcount -le 15 ] || fatal_error "More than 15 entries in port list ($ports)"
2005-07-09 06:45:32 +02:00
ports="-m multiport --dports $ports"
else
fatal_error "Port Ranges require multiport match support in your kernel ($ports)"
fi
;;
esac
else
ports="--dport $ports"
fi
fi
;;
*)
[ -n "$ports" ] && fatal_error "Ports only allowed with UDP or TCP ($ports)"
;;
esac
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
proto="-p $proto"
else
displayproto="(all)"
[ -n "$ports" ] && fatal_error "Ports only allowed with UDP or TCP ($ports)"
2005-09-19 16:43:22 +02:00
fi
2005-07-09 06:45:32 +02:00
2005-07-09 07:45:05 +02:00
destination=${destnets:=0.0.0.0/0}
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
[ -z "$pre_nat" ] && chain=$(masq_chain $interface) || chain=$(snat_chain $interface)
2003-02-23 15:10:37 +01:00
2004-01-22 03:06:56 +01:00
case $destnets in
!*)
destnets=${destnets#!}
2005-09-19 16:43:22 +02:00
2005-08-30 17:54:29 +02:00
if [ $COMMAND != check ]; then
build_exclusion_chain newchain nat "$nomasq" "$destnets"
2005-08-11 03:40:50 +02:00
2005-08-30 17:54:29 +02:00
if [ -n "$networks" ]; then
for s in $networks; do
addnatrule $chain $(source_ip_range $s) $proto $ports $policy -j $newchain
done
networks=
else
addnatrule $chain -j $newchain
fi
2004-01-22 03:06:56 +01:00
else
2005-08-30 17:54:29 +02:00
networks=
2004-01-22 03:06:56 +01:00
fi
2002-05-01 01:13:15 +02:00
2004-01-22 03:06:56 +01:00
chain=$newchain
destnets=0.0.0.0/0
2005-07-09 06:45:32 +02:00
proto=
ports=
2005-07-09 07:45:05 +02:00
policy=
2003-02-23 15:10:37 +01:00
2005-08-05 17:52:03 +02:00
[ -n "$nomasq" ] && source="$source except $nomasq"
2004-01-22 03:06:56 +01:00
;;
*)
if [ -n "$nomasq" ]; then
2005-08-30 17:54:29 +02:00
if [ $COMMAND != check ]; then
build_exclusion_chain newchain nat $nomasq
2005-09-19 16:17:29 +02:00
2005-08-30 17:54:29 +02:00
if [ -n "$networks" ]; then
for s in $networks; do
for destnet in $(separate_list $destnets); do
addnatrule $chain $(both_ip_ranges $s $destnet) $proto $ports $policy -j $newchain
done
done
else
2004-01-22 03:06:56 +01:00
for destnet in $(separate_list $destnets); do
2005-08-30 17:54:29 +02:00
addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $newchain
2004-01-22 03:06:56 +01:00
done
2005-08-30 17:54:29 +02:00
fi
2004-01-22 03:06:56 +01:00
fi
chain=$newchain
2005-07-09 06:45:32 +02:00
networks=
2004-01-22 03:06:56 +01:00
destnets=0.0.0.0/0
2005-07-09 06:45:32 +02:00
proto=
ports=
2005-07-09 07:45:05 +02:00
policy=
2004-01-22 03:06:56 +01:00
source="$source except $nomasq"
fi
;;
esac
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
addrlist=
2005-07-09 07:45:05 +02:00
target=MASQUERADE
2005-07-09 06:45:32 +02:00
2003-08-07 01:50:33 +02:00
if [ -n "$addresses" ]; then
2005-07-09 07:45:05 +02:00
case "$addresses" in
SAME:nodst:*)
target="SAME --nodst"
addresses=${addresses#SAME:nodst:}
for address in $(separate_list $addresses); do
addrlist="$addrlist --to $address";
done
;;
SAME:*)
target="SAME"
addresses=${addresses#SAME:}
for address in $(separate_list $addresses); do
addrlist="$addrlist --to $address";
done
;;
*)
for address in $(separate_list $addresses); do
case $address in
*.*.*.*)
target=SNAT
addrlist="$addrlist --to-source $address"
;;
*)
addrlist="$addrlist --to-ports ${address#:}"
;;
esac
done
;;
esac
2003-08-07 01:50:33 +02:00
fi
2005-07-09 06:45:32 +02:00
if [ -n "$networks" ]; then
2005-07-09 07:45:05 +02:00
for network in $networks; do
2005-08-30 17:54:29 +02:00
if [ $COMMAND != check ]; then
for destnet in $(separate_list $destnets); do
addnatrule $chain $(both_ip_ranges $network $destnet) $proto $ports $policy -j $target $addrlist
done
fi
2005-07-09 07:45:05 +02:00
2004-01-22 17:59:40 +01:00
if [ -n "$addresses" ]; then
2005-07-09 07:45:05 +02:00
progress_message " To $destination $displayproto from $network through ${interface} using $addresses"
2004-01-22 17:59:40 +01:00
else
2005-07-09 07:45:05 +02:00
progress_message " To $destination $displayproto from $network through ${interface}"
2004-01-22 17:59:40 +01:00
fi
2003-01-24 23:47:22 +01:00
done
2002-05-01 01:13:15 +02:00
else
2005-08-30 17:54:29 +02:00
if [ $COMMAND != check ]; then
for destnet in $(separate_list $destnets); do
addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $target $addrlist
done
fi
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ -n "$addresses" ]; then
progress_message " To $destination $displayproto from $source through ${interface} using $addresses"
else
progress_message " To $destination $displayproto from $source through ${interface}"
fi
2002-05-01 01:13:15 +02:00
fi
}
strip_file masq $1
2005-07-09 07:45:05 +02:00
if [ -n "$NAT_ENABLED" ]; then
echo "Masqueraded Networks and Hosts:"
2005-08-30 17:54:29 +02:00
[ -n "$RETAIN_ALIASES" -o $COMMAND = check ] || save_progress_message "Restoring Masquerading/SNAT..."
2005-07-09 07:45:05 +02:00
fi
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
while read fullinterface networks addresses proto ports ipsec; do
expandv fullinterface networks addresses proto ports ipsec
2002-05-01 01:13:15 +02:00
[ -n "$NAT_ENABLED" ] && setup_one || \
2005-07-26 01:08:09 +02:00
error_message "WARNING: NAT disabled; masq rule ignored"
2002-05-01 01:13:15 +02:00
done < $TMP_DIR/masq
}
2002-10-23 18:48:40 +02:00
#
# Add a record to the blacklst chain
#
# $source = address match
# $proto = protocol selector
# $dport = destination port selector
#
2002-09-15 01:40:46 +02:00
add_blacklist_rule() {
2005-07-09 07:55:29 +02:00
if [ "$COMMAND" != check ]; then
if [ -n "$BLACKLIST_LOGLEVEL" ]; then
log_rule $BLACKLIST_LOGLEVEL blacklst $BLACKLIST_DISPOSITION $(fix_bang $source $proto $dport)
fi
2005-09-19 16:17:29 +02:00
2005-07-09 07:55:29 +02:00
run_iptables2 -A blacklst $source $proto $dport -j $disposition
2002-12-13 04:23:46 +01:00
fi
2002-09-15 01:40:46 +02:00
}
2002-05-01 01:13:15 +02:00
2002-10-23 18:48:40 +02:00
#
# Process a record from the blacklist file
#
2005-07-09 06:45:32 +02:00
# $networks = address/networks
2002-10-23 18:48:40 +02:00
# $protocol = Protocol Number/Name
# $port = Port Number/Name
#
2002-05-01 01:13:15 +02:00
process_blacklist_rec() {
local source
local addr
2002-09-15 01:40:46 +02:00
local proto
2002-09-15 00:00:52 +02:00
local dport
2005-07-09 07:55:29 +02:00
local temp
local setname
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
for addr in $(separate_list $networks); do
2002-05-01 01:13:15 +02:00
case $addr in
2005-07-09 07:55:29 +02:00
~*)
addr=$(echo $addr | sed 's/~//;s/-/:/g')
source="--match mac --mac-source $addr"
;;
*)
source="$(source_ip_range $addr)"
;;
2002-07-06 00:24:40 +02:00
esac
2003-02-23 15:10:37 +01:00
2002-09-15 00:00:52 +02:00
if [ -n "$protocol" ]; then
proto=" -p $protocol "
2002-05-01 01:13:15 +02:00
2002-09-15 01:40:46 +02:00
case $protocol in
tcp|TCP|6|udp|UDP|17)
2003-02-23 15:10:37 +01:00
if [ -n "$ports" ]; then
2002-09-15 01:40:46 +02:00
if [ -n "$MULTIPORT" -a \
"$ports" != "${ports%,*}" -a \
"$ports" = "${ports%:*}" -a \
2005-07-09 06:45:32 +02:00
$(list_count $ports) -le 15 ]
2002-09-15 01:40:46 +02:00
then
dport="-m multiport --dports $ports"
add_blacklist_rule
else
2005-07-09 06:45:32 +02:00
for dport in $(separate_list $ports); do
2002-09-15 01:40:46 +02:00
dport="--dport $dport"
add_blacklist_rule
done
fi
else
add_blacklist_rule
fi
;;
icmp|ICMP|0)
if [ -n "$ports" ]; then
2005-07-09 06:45:32 +02:00
for dport in $(separate_list $ports); do
2002-09-15 01:40:46 +02:00
dport="--icmp-type $dport"
add_blacklist_rule
done
else
add_blacklist_rule
fi
;;
*)
add_blacklist_rule
;;
esac
else
add_blacklist_rule
fi
2002-09-15 00:00:52 +02:00
2002-09-15 01:40:46 +02:00
if [ -n "$ports" ]; then
addr="$addr $protocol $ports"
2002-09-15 00:00:52 +02:00
elif [ -n "$protocol" ]; then
addr="$addr $protocol"
fi
2003-02-23 15:10:37 +01:00
2005-07-09 07:55:29 +02:00
if [ "$COMMAND" = check ]; then
progress_message " $addr" Verified
else
progress_message " $addr added to Black List"
fi
2002-05-01 01:13:15 +02:00
done
}
2002-10-23 18:48:40 +02:00
#
# Setup the Black List
#
2002-05-01 01:13:15 +02:00
setup_blacklist() {
2005-07-09 06:45:32 +02:00
local hosts="$(find_hosts_by_option blacklist)"
local f=$(find_file blacklist)
2002-05-01 01:13:15 +02:00
local disposition=$BLACKLIST_DISPOSITION
2005-07-09 07:45:05 +02:00
local ipsec policy
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
if [ -n "$hosts" -a -f $f ]; then
2002-07-06 00:24:40 +02:00
echo "Setting up Blacklisting..."
2002-05-01 01:13:15 +02:00
strip_file blacklist $f
createchain blacklst no
2005-07-09 06:45:32 +02:00
[ -n "$BLACKLISTNEWONLY" ] && state="-m state --state NEW,INVALID" || state=
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
for host in $hosts; do
2005-07-09 07:45:05 +02:00
ipsec=${host%^*}
host=${host#*^}
[ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy=
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
network=${host#*:}
for chain in $(first_chains $interface); do
2005-07-09 07:45:05 +02:00
run_iptables -A $chain $state $(match_source_hosts $network) $policy -j blacklst
2002-05-18 15:45:23 +02:00
done
2005-09-19 16:43:22 +02:00
2005-07-09 06:45:32 +02:00
[ $network = 0/0.0.0.0 ] && network= || network=":$network"
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
progress_message " Blacklisting enabled on ${interface}${network}"
2002-05-01 01:13:15 +02:00
done
[ "$disposition" = REJECT ] && disposition=reject
2005-07-09 07:45:05 +02:00
if [ -z "$DELAYBLACKLISTLOAD" ]; then
while read networks protocol ports; do
expandv networks protocol ports
process_blacklist_rec
done < $TMP_DIR/blacklist
fi
2002-05-01 01:13:15 +02:00
fi
}
2002-10-23 18:48:40 +02:00
#
# Refresh the Black List
#
2002-05-01 01:13:15 +02:00
refresh_blacklist() {
2005-07-09 06:45:32 +02:00
local f=$(find_file blacklist)
2002-05-01 01:13:15 +02:00
local disposition=$BLACKLIST_DISPOSITION
2005-07-09 07:45:05 +02:00
if qt $IPTABLES -L blacklst -n ; then
echo "Loading Black List..."
2002-05-01 01:13:15 +02:00
strip_file blacklist $f
[ "$disposition" = REJECT ] && disposition=reject
run_iptables -F blacklst
2005-07-09 06:45:32 +02:00
while read networks protocol ports; do
expandv networks protocol ports
2002-05-01 01:13:15 +02:00
process_blacklist_rec
done < $TMP_DIR/blacklist
fi
}
2005-07-09 07:55:29 +02:00
#
# Verify the Black List
#
validate_blacklist() {
local f=$(find_file blacklist)
local disposition=$BLACKLIST_DISPOSITION
echo "Checking Black List..."
strip_file blacklist $f
[ "$disposition" = REJECT ] && disposition=reject
while read networks protocol ports; do
expandv networks protocol ports
process_blacklist_rec
done < $TMP_DIR/blacklist
}
2002-10-23 18:48:40 +02:00
#
# Verify that kernel has netfilter support
#
2002-05-01 01:13:15 +02:00
verify_os_version() {
2005-07-09 06:45:32 +02:00
osversion=$(uname -r)
2002-05-01 01:13:15 +02:00
case $osversion in
2003-07-05 18:24:41 +02:00
2.4.*|2.5.*|2.6.*)
2002-07-06 00:24:40 +02:00
;;
2002-05-01 01:13:15 +02:00
*)
startup_error "Shorewall version $version does not work with kernel version $osversion"
;;
esac
2003-03-11 15:55:01 +01:00
2005-07-09 06:45:32 +02:00
[ $COMMAND = start -a -n "$(lsmod 2> /dev/null | grep '^ipchains')" ] && \
2003-03-11 15:55:01 +01:00
startup_error "Shorewall can't start with the ipchains kernel module loaded - see FAQ #8"
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Add IP Aliases
#
2002-07-29 16:31:50 +02:00
add_ip_aliases()
2002-07-23 18:26:45 +02:00
{
2005-07-28 00:13:25 +02:00
local addresses external interface inet cidr rest val arping=$(mywhich arping)
2002-10-22 02:13:24 +02:00
2005-08-02 18:46:30 +02:00
address_details()
2002-07-23 18:26:45 +02:00
{
#
# Folks feel uneasy if they don't see all of the same
# decoration on these IP addresses that they see when their
# distro's net config tool adds them. In an attempt to reduce
# the anxiety level, we have the following code which sets
2005-07-09 06:45:32 +02:00
# the VLSM and BRD from an existing address in the same networks
2002-07-23 18:26:45 +02:00
#
2005-08-02 18:46:30 +02:00
# Get all of the lines that contain inet addresses with broadcast
2002-07-23 18:26:45 +02:00
#
2005-07-09 06:45:32 +02:00
ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | while read inet cidr rest ; do
2003-08-05 17:05:45 +02:00
case $cidr in
*/*)
2005-07-09 06:45:32 +02:00
if in_network $external $cidr; then
echo "/${cidr#*/} brd $(broadcastaddress $cidr)"
2003-08-05 17:05:45 +02:00
break
fi
;;
esac
2003-06-22 18:58:33 +02:00
done
2003-06-23 02:42:28 +02:00
}
2002-07-23 18:26:45 +02:00
2003-06-23 02:42:28 +02:00
do_one()
{
2005-07-09 06:45:32 +02:00
val=$(address_details)
2005-07-09 07:45:05 +02:00
if [ -n "$RETAIN_ALIASES" ]; then
run_ip addr add ${external}${val} dev $interface $label
save_command qt ip addr add ${external}${val} dev $interface $label
else
ensure_and_save_command ip addr add ${external}${val} dev $interface $label
fi
2005-07-28 00:41:52 +02:00
[ -n "$arping" ] && run_and_save_command qt $arping -U -c 2 -I $interface $external
2005-07-27 22:30:16 +02:00
2005-07-26 01:08:09 +02:00
echo "$external $interface" >> /var/lib/shorewall/nat
2003-01-24 20:42:23 +01:00
[ -n "$label" ] && label="with $label"
2005-07-09 06:45:32 +02:00
progress_message " IP Address $external added to interface $interface $label"
2002-07-23 18:26:45 +02:00
}
2005-08-23 22:41:18 +02:00
set -- $ALIASES_TO_ADD
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
save_progress_message "Restoring IP Addresses..."
2002-07-23 18:26:45 +02:00
while [ $# -gt 0 ]; do
external=$1
interface=$2
2003-01-24 20:42:23 +01:00
label=
if [ "$interface" != "${interface%:*}" ]; then
label="${interface#*:}"
interface="${interface%:*}"
label="label $interface:$label"
fi
2003-02-23 15:10:37 +01:00
2002-07-23 18:26:45 +02:00
shift;shift
2003-06-23 00:56:25 +02:00
2005-07-09 06:45:32 +02:00
list_search $external $(find_interface_addresses $interface) || do_one
2002-07-23 18:26:45 +02:00
done
}
2002-10-23 18:48:40 +02:00
#
# Load kernel modules required for Shorewall
#
2005-07-09 06:45:32 +02:00
load_kernel_modules()
{
save_modules_dir=$MODULESDIR
2002-05-01 01:13:15 +02:00
2002-10-23 18:48:40 +02:00
[ -z "$MODULESDIR" ] && \
2005-07-09 06:45:32 +02:00
MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv4/netfilter
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
modules=$(find_file modules)
2002-05-01 01:13:15 +02:00
if [ -f $modules -a -d $MODULESDIR ]; then
2005-09-19 16:17:29 +02:00
progress_message "Loading Modules..."
2002-05-01 01:13:15 +02:00
. $modules
fi
2005-07-09 06:45:32 +02:00
MODULESDIR=$save_modules_dir
}
save_load_kernel_modules()
{
modules=$(find_file modules)
save_progress_message "Loading kernel modules..."
save_command "reload_kernel_modules <<__EOF__"
while read command; do
case "$command" in
loadmodule*)
save_command $command
;;
esac
done < $modules
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
save_command __EOF__
2005-07-09 07:45:05 +02:00
save_command ""
2005-07-09 06:45:32 +02:00
2002-05-01 01:13:15 +02:00
}
2003-02-21 23:55:36 +01:00
# Verify that the 'ip' program is installed
verify_ip() {
2003-06-18 20:26:05 +02:00
qt ip link ls ||\
2003-02-21 23:55:36 +01:00
startup_error "Shorewall $version requires the iproute package ('ip' utility)"
}
2002-10-23 18:48:40 +02:00
#
# Perform Initialization
# - Delete all old rules
# - Delete all user chains
# - Set the POLICY on all standard chains and add a rule to allow packets
# that are part of established connections
2002-07-06 00:24:40 +02:00
# - Determine the zones
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
initialize_netfilter () {
2003-06-27 23:02:52 +02:00
report_capabilities
2005-07-09 07:45:05 +02:00
if [ -n "$BRIDGING" ]; then
[ -n "$PHYSDEV_MATCH" ] || startup_error "BRIDGING=Yes requires Physdev Match support in your Kernel and iptables"
fi
[ "$MACLIST_TTL" = "0" ] && MACLIST_TTL=
2005-07-18 00:08:15 +02:00
if [ -n "$MACLIST_TTL" -a -z "$RECENT_MATCH" ]; then
2005-07-26 01:08:09 +02:00
startup_error "MACLIST_TTL requires the Recent Match capability which is not present in your Kernel and/or iptables"
2005-07-09 07:45:05 +02:00
fi
[ -n "$RFC1918_STRICT" -a -z "$CONNTRACK_MATCH" ] && \
startup_error "RFC1918_STRICT=Yes requires Connection Tracking match"
2002-05-01 01:13:15 +02:00
echo "Determining Zones..."
determine_zones
2005-10-04 16:54:56 +02:00
display_list "IPv4 Zones:" $IPV4_ZONES
[ -n "$IPSEC_ZONES" ] && \
display_list "IPSEC Zones:" $IPSEC_ZONES
display_list "Firewall Zone:" $FW
2002-05-01 01:13:15 +02:00
echo "Validating interfaces file..."
validate_interfaces_file
echo "Validating hosts file..."
validate_hosts_file
2002-07-10 00:39:22 +02:00
echo "Validating Policy file..."
validate_policy
2002-05-01 01:13:15 +02:00
echo "Determining Hosts in Zones..."
determine_interfaces
determine_hosts
2003-02-23 15:10:37 +01:00
2003-02-13 15:59:34 +01:00
run_user_exit init
2003-02-08 21:58:44 +01:00
#
2005-07-09 07:45:05 +02:00
# Some files might be large so strip them while the firewall is still running
2003-02-08 21:58:44 +01:00
# (restart command). This reduces the length of time that the firewall isn't
# accepting new connections.
#
2003-02-23 15:10:37 +01:00
2003-02-08 21:58:44 +01:00
strip_file rules
strip_file proxyarp
strip_file maclist
strip_file nat
2005-07-09 06:45:32 +02:00
strip_file netmap
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
echo "Pre-processing Actions..."
process_actions1
2005-08-01 19:17:24 +02:00
TERMINATOR=fatal_error
2003-02-23 15:10:37 +01:00
2002-05-01 01:13:15 +02:00
deletechain shorewall
[ -n "$NAT_ENABLED" ] && delete_nat
delete_proxy_arp
[ -n "$MANGLE_ENABLED" ] && \
run_iptables -t mangle -F && \
run_iptables -t mangle -X
2005-08-25 00:39:19 +02:00
[ -n "$RAW_TABLE" ] && \
run_iptables -t raw -F && \
run_iptables -t raw -X
2002-12-31 17:04:31 +01:00
[ -n "$CLEAR_TC" ] && delete_tc
2002-05-01 01:13:15 +02:00
echo "Deleting user chains..."
2005-07-09 07:45:05 +02:00
exists_INPUT=Yes
exists_OUTPUT=Yes
exists_FORWARD=Yes
2005-08-02 18:46:30 +02:00
2005-07-26 01:08:09 +02:00
process_criticalhosts
if [ -n "$CRITICALHOSTS" ]; then
2005-08-02 18:46:30 +02:00
2005-07-26 01:08:09 +02:00
setpolicy INPUT ACCEPT
setpolicy OUTPUT ACCEPT
setpolicy FORWARD DROP
2005-09-19 16:17:29 +02:00
2005-07-26 01:08:09 +02:00
deleteallchains
enable_critical_hosts
2005-09-19 16:43:22 +02:00
2005-09-19 16:17:29 +02:00
setpolicy INPUT DROP
2005-07-26 01:08:09 +02:00
setpolicy OUTPUT DROP
setcontinue FORWARD
setcontinue INPUT
setcontinue OUTPUT
else
setpolicy INPUT DROP
setpolicy OUTPUT DROP
setpolicy FORWARD DROP
2005-09-19 16:17:29 +02:00
2005-07-26 01:08:09 +02:00
deleteallchains
2005-09-19 16:17:29 +02:00
2005-07-26 01:08:09 +02:00
setcontinue FORWARD
setcontinue INPUT
setcontinue OUTPUT
fi
2003-03-29 15:37:50 +01:00
2005-07-09 07:55:29 +02:00
f=$(find_file ipsets)
if [ -f $f ]; then
echo "Processing $f ..."
ipset -U :all: :all:
run_ipset -F
run_ipset -X
run_ipset -R < $f
fi
2005-07-09 07:45:05 +02:00
run_user_exit continue
f=$(find_file routestopped)
echo "Processing $f ..."
strip_file routestopped $f
process_routestopped -A
2005-07-09 06:45:32 +02:00
[ -n "$DISABLE_IPV6" ] && disable_ipv6
2003-05-16 17:19:57 +02:00
#
2005-07-09 06:45:32 +02:00
# Enable the Loopback interface for now
2003-05-16 17:19:57 +02:00
#
run_iptables -A INPUT -i lo -j ACCEPT
run_iptables -A OUTPUT -o lo -j ACCEPT
2005-08-02 18:46:30 +02:00
2003-05-16 17:19:57 +02:00
2002-09-25 01:13:36 +02:00
#
2005-07-09 07:45:05 +02:00
# Allow DNS lookups during startup for FQDNs
2002-09-25 01:13:36 +02:00
#
2002-05-01 01:13:15 +02:00
2003-03-10 01:41:39 +01:00
for chain in INPUT OUTPUT FORWARD; do
run_iptables -A $chain -p udp --dport 53 -j ACCEPT
done
2003-03-24 22:56:31 +01:00
2005-07-09 07:45:05 +02:00
if [ -n "$CLAMPMSS" ]; then
case $CLAMPMSS in
Yes)
option="--clamp-mss-to-pmtu"
;;
*)
option="--set-mss $CLAMPMSS"
;;
esac
run_iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS $option
fi
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
accounting_file=$(find_file accounting)
[ -f $accounting_file ] && setup_accounting $accounting_file
2003-02-23 15:10:37 +01:00
2003-06-12 01:57:35 +02:00
createchain reject no
2002-06-04 22:17:46 +02:00
createchain dynamic no
2005-07-09 06:45:32 +02:00
createchain smurfs no
2003-08-21 15:18:51 +02:00
2003-08-24 03:24:23 +02:00
if [ -f /var/lib/shorewall/save ]; then
2002-07-06 00:24:40 +02:00
echo "Restoring dynamic rules..."
2005-09-19 16:43:22 +02:00
2003-07-26 18:44:38 +02:00
if [ -f /var/lib/shorewall/save ]; then
while read target ignore1 ignore2 address rest; do
case $target in
DROP|reject)
2005-07-09 07:45:05 +02:00
run_iptables -A dynamic -s $address -j $target
2003-07-26 18:44:38 +02:00
;;
*)
;;
esac
done < /var/lib/shorewall/save
fi
2002-06-04 22:17:46 +02:00
fi
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
[ -n "$BLACKLISTNEWONLY" ] && state="-m state --state NEW,INVALID" || state=
2003-10-11 18:06:00 +02:00
2003-07-03 01:12:14 +02:00
echo "Creating Interface Chains..."
2002-06-04 22:17:46 +02:00
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
createchain $(forward_chain $interface) no
run_iptables -A $(forward_chain $interface) $state -j dynamic
createchain $(input_chain $interface) no
run_iptables -A $(input_chain $interface) $state -j dynamic
2002-05-18 15:45:23 +02:00
done
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Construct zone-independent rules
#
2002-05-01 01:13:15 +02:00
add_common_rules() {
2003-05-22 22:37:24 +02:00
local savelogparms="$LOGPARMS"
2004-01-27 23:33:32 +01:00
local broadcasts="$(find_broadcasts) 255.255.255.255 224.0.0.0/4"
2005-07-09 06:45:32 +02:00
drop_broadcasts() {
2004-01-27 23:33:32 +01:00
for address in $broadcasts ; do
2004-01-27 22:16:07 +01:00
run_iptables -A reject -d $address -j DROP
done
2005-07-09 06:45:32 +02:00
}
#
# Populate the smurf chain
#
for address in $broadcasts ; do
[ -n "$SMURF_LOG_LEVEL" ] && log_rule $SMURF_LOG_LEVEL smurfs DROP -s $address
2005-07-09 07:45:05 +02:00
run_iptables -A smurfs $(source_ip_range $address) -j DROP
2005-07-09 06:45:32 +02:00
done
#
# Reject Rules -- Don't respond to broadcasts with an ICMP
#
2005-08-14 21:26:17 +02:00
if [ -n "$USEPKTTYPE" ]; then
2005-07-09 07:45:05 +02:00
qt $IPTABLES -A reject -m pkttype --pkt-type broadcast -j DROP
if ! qt $IPTABLES -A reject -m pkttype --pkt-type multicast -j DROP; then
2005-07-09 06:45:32 +02:00
#
# No pkttype support -- do it the hard way
#
drop_broadcasts
fi
else
drop_broadcasts
2004-01-27 22:16:07 +01:00
fi
2004-01-27 23:33:32 +01:00
#
# Don't feed the smurfs
#
for address in $broadcasts ; do
run_iptables -A reject -s $address -j DROP
2005-08-02 18:46:30 +02:00
done
2005-07-09 06:45:32 +02:00
2004-01-27 23:33:32 +01:00
run_iptables -A reject -p tcp -j REJECT --reject-with tcp-reset
2003-04-14 02:47:47 +02:00
run_iptables -A reject -p udp -j REJECT
2003-04-14 03:01:01 +02:00
#
# Not all versions of iptables support these so don't complain if they don't work
#
2005-07-09 07:45:05 +02:00
qt $IPTABLES -A reject -p icmp -j REJECT --reject-with icmp-host-unreachable
if ! qt $IPTABLES -A reject -j REJECT --reject-with icmp-host-prohibited; then
2003-04-16 18:54:46 +02:00
#
# In case the above doesn't work
#
run_iptables -A reject -j REJECT
fi
2003-05-21 23:36:05 +02:00
2005-07-09 07:45:05 +02:00
#
# Create common action chains
#
for action in $USEDACTIONS; do
createactionchain $action
done
2005-07-09 06:45:32 +02:00
run_user_exit initdone
2003-05-21 23:36:05 +02:00
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Process Black List
2002-05-01 01:13:15 +02:00
#
2005-07-09 06:45:32 +02:00
setup_blacklist
2003-05-21 23:36:05 +02:00
2005-07-09 06:45:32 +02:00
#
# SMURFS
#
hosts=$(find_hosts_by_option nosmurfs)
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
if [ -n "$hosts" ]; then
2005-09-18 00:37:32 +02:00
2005-07-09 06:45:32 +02:00
echo "Adding Anti-smurf Rules"
2003-05-21 23:36:05 +02:00
2005-07-09 06:45:32 +02:00
for host in $hosts; do
2005-07-09 07:45:05 +02:00
ipsec=${host%^*}
host=${host#*^}
[ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy=
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
network=${host#*:}
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
for chain in $(first_chains $interface); do
2005-07-09 07:45:05 +02:00
run_iptables -A $chain -m state --state NEW,INVALID $(match_source_hosts $network) $policy -j smurfs
2002-05-01 01:13:15 +02:00
done
done
fi
2002-10-23 18:48:40 +02:00
#
2002-08-24 17:09:34 +02:00
# DHCP
#
2005-07-09 06:45:32 +02:00
interfaces=$(find_interfaces_by_option dhcp)
2002-08-24 17:09:34 +02:00
2003-07-19 01:12:34 +02:00
if [ -n "$interfaces" ]; then
echo "Adding rules for DHCP"
2002-08-24 17:09:34 +02:00
2003-07-19 01:12:34 +02:00
for interface in $interfaces; do
2005-07-09 06:45:32 +02:00
if [ -n "$BRIDGING" ]; then
2005-07-13 17:26:51 +02:00
is_bridge=$( brctl show $interface 2> /dev/null | grep ^$interface[[:space:]] )
2005-07-09 06:45:32 +02:00
[ -n "$is_bridge" ] && \
2005-07-09 07:45:05 +02:00
$IPTABLES -A $(forward_chain $interface) -p udp -o $interface --dport 67:68 -j ACCEPT
2005-07-09 06:45:32 +02:00
fi
run_iptables -A $(input_chain $interface) -p udp --dport 67:68 -j ACCEPT
2005-07-09 07:45:05 +02:00
run_iptables -A OUTPUT -o $interface -p udp --dport 67:68 -j ACCEPT
2003-07-19 01:12:34 +02:00
done
fi
2002-10-23 18:48:40 +02:00
#
2002-06-19 23:51:36 +02:00
# RFC 1918
#
2005-07-09 06:45:32 +02:00
hosts="$(find_hosts_by_option norfc1918)"
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
if [ -n "$hosts" ]; then
2002-05-01 01:13:15 +02:00
echo "Enabling RFC1918 Filtering"
2003-02-23 15:10:37 +01:00
2002-05-31 16:33:18 +02:00
strip_file rfc1918
2003-02-23 15:10:37 +01:00
2003-11-27 19:39:11 +01:00
createchain norfc1918 no
2002-05-01 01:13:15 +02:00
2003-11-27 19:39:11 +01:00
createchain rfc1918 no
2005-09-19 16:43:22 +02:00
2003-11-27 19:39:11 +01:00
log_rule $RFC1918_LOG_LEVEL rfc1918 DROP
2005-09-19 16:43:22 +02:00
2003-11-27 19:39:11 +01:00
run_iptables -A rfc1918 -j DROP
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
chain=norfc1918
if [ -n "$RFC1918_STRICT" ]; then
#
# We'll generate two chains - one for source and one for destination
#
chain=rfc1918d
2005-09-19 16:43:22 +02:00
createchain $chain no
2005-07-09 07:45:05 +02:00
elif [ -n "$MANGLE_ENABLED" -a -z "$CONNTRACK_MATCH" ]; then
2002-10-23 18:48:40 +02:00
#
2005-08-02 18:46:30 +02:00
# Mangling is enabled but conntrack match isn't available --
2003-06-27 23:02:52 +02:00
# create a chain in the mangle table to filter RFC1918 destination
# addresses. This must be done in the mangle table before we apply
# any DNAT rules in the nat table
2002-05-01 01:13:15 +02:00
#
# Also add a chain to log and drop any RFC1918 packets that we find
#
2002-06-21 19:20:18 +02:00
run_iptables -t mangle -N man1918
2003-11-27 19:39:11 +01:00
run_iptables -t mangle -N rfc1918
log_rule $RFC1918_LOG_LEVEL rfc1918 DROP -t mangle
run_iptables -t mangle -A rfc1918 -j DROP
2002-05-01 01:13:15 +02:00
fi
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
while read networks target; do
2002-06-21 23:40:36 +02:00
case $target in
2003-11-27 19:39:11 +01:00
logdrop)
target=rfc1918
2005-07-09 07:45:05 +02:00
s_target=rfc1918
2003-11-27 19:39:11 +01:00
;;
2005-07-09 07:45:05 +02:00
DROP)
s_target=DROP
;;
RETURN)
[ -n "$RFC1918_STRICT" ] && s_target=rfc1918d || s_target=RETURN
2002-06-21 23:40:36 +02:00
;;
*)
2005-07-09 06:45:32 +02:00
fatal_error "Invalid target ($target) for $networks"
2002-06-21 23:40:36 +02:00
;;
esac
2005-07-09 07:45:05 +02:00
for network in $(separate_list $networks); do
run_iptables2 -A norfc1918 $(source_ip_range $network) -j $s_target
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ -n "$CONNTRACK_MATCH" ]; then
#
# We have connection tracking match -- match on the original destination
#
run_iptables2 -A $chain -m conntrack --ctorigdst $network -j $target
elif [ -n "$MANGLE_ENABLED" ]; then
#
# No connection tracking match but we have mangling -- add a rule to
# the mangle table
#
run_iptables2 -t mangle -A man1918 $(dest_ip_range $network) -j $target
fi
done
2002-05-31 16:33:18 +02:00
done < $TMP_DIR/rfc1918
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
[ -n "$RFC1918_STRICT" ] && run_iptables -A norfc1918 -j rfc1918d
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
for host in $hosts; do
2005-07-09 07:45:05 +02:00
ipsec=${host%^*}
host=${host#*^}
[ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy=
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
networks=${host#*:}
for chain in $(first_chains $interface); do
2005-07-09 07:45:05 +02:00
run_iptables -A $chain -m state --state NEW $(match_source_hosts $networks) $policy -j norfc1918
2002-05-18 15:45:23 +02:00
done
2003-02-23 15:10:37 +01:00
2003-06-27 23:02:52 +02:00
[ -n "$MANGLE_ENABLED" -a -z "$CONNTRACK_MATCH" ] && \
2005-07-09 06:45:32 +02:00
run_iptables -t mangle -A PREROUTING -m state --state NEW -i $interface $(match_source_hosts $networks) -j man1918
done
fi
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
hosts=$(find_hosts_by_option tcpflags)
2002-11-10 22:34:20 +01:00
2005-07-09 06:45:32 +02:00
if [ -n "$hosts" ]; then
2002-11-10 22:34:20 +01:00
echo "Setting up TCP Flags checking..."
2003-02-23 15:10:37 +01:00
2002-11-10 22:34:20 +01:00
createchain tcpflags no
if [ -n "$TCP_FLAGS_LOG_LEVEL" ]; then
createchain logflags no
2003-05-21 23:36:05 +02:00
savelogparms="$LOGPARMS"
2005-07-12 02:42:08 +02:00
[ "$TCP_FLAGS_LOG_LEVEL" = ULOG ] || LOGPARMS="$LOGPARMS --log-ip-options"
2003-05-21 23:36:05 +02:00
2005-08-02 18:46:30 +02:00
log_rule $TCP_FLAGS_LOG_LEVEL logflags $TCP_FLAGS_DISPOSITION
2003-05-21 23:36:05 +02:00
LOGPARMS="$savelogparms"
2005-09-18 00:37:32 +02:00
2002-11-10 22:34:20 +01:00
case $TCP_FLAGS_DISPOSITION in
REJECT)
2003-06-12 01:57:35 +02:00
run_iptables -A logflags -j REJECT --reject-with tcp-reset
2002-11-10 22:34:20 +01:00
;;
*)
run_iptables -A logflags -j $TCP_FLAGS_DISPOSITION
;;
esac
disposition="-j logflags"
else
disposition="-j $TCP_FLAGS_DISPOSITION"
fi
run_iptables -A tcpflags -p tcp --tcp-flags ALL FIN,URG,PSH $disposition
run_iptables -A tcpflags -p tcp --tcp-flags ALL NONE $disposition
run_iptables -A tcpflags -p tcp --tcp-flags SYN,RST SYN,RST $disposition
run_iptables -A tcpflags -p tcp --tcp-flags SYN,FIN SYN,FIN $disposition
2002-12-14 16:44:26 +01:00
#
2002-12-20 02:13:41 +01:00
# There are a lot of probes to ports 80, 3128 and 8080 that use a source
# port of 0. This catches them even if they are directed at an IP that
# hosts a web server.
2002-12-14 16:44:26 +01:00
#
run_iptables -A tcpflags -p tcp --syn --sport 0 $disposition
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
for host in $hosts; do
2005-07-09 07:45:05 +02:00
ipsec=${host%^*}
host=${host#*^}
[ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy=
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
network=${host#*:}
for chain in $(first_chains $interface); do
2005-07-09 07:45:05 +02:00
run_iptables -A $chain -p tcp $(match_source_hosts $network) $policy -j tcpflags
2002-11-10 22:34:20 +01:00
done
done
fi
2002-10-23 18:48:40 +02:00
#
2003-08-08 22:55:06 +02:00
# ARP Filtering
#
2005-07-09 06:45:32 +02:00
save_progress_message "Restoring ARP filtering..."
2005-07-09 07:45:05 +02:00
for f in /proc/sys/net/ipv4/conf/*; do
run_and_save_command "[ -f $f/arp_filter ] && echo 0 > $f/arp_filter"
2005-07-26 01:08:09 +02:00
run_and_save_command "[ -f $f/arp_filter ] && echo 0 > $f/arp_ignore"
2003-08-08 22:55:06 +02:00
done
2005-07-09 06:45:32 +02:00
interfaces=$(find_interfaces_by_option arp_filter)
2005-07-26 01:08:09 +02:00
interfaces1=$(find_interfaces_by_option1 arp_ignore)
2003-08-08 22:55:06 +02:00
2005-07-26 01:08:09 +02:00
if [ -n "${interfaces}${interfaces1}" ]; then
2003-08-08 22:55:06 +02:00
echo "Setting up ARP Filtering..."
2005-09-19 16:43:22 +02:00
2003-08-08 22:55:06 +02:00
for interface in $interfaces; do
file=/proc/sys/net/ipv4/conf/$interface/arp_filter
if [ -f $file ]; then
2005-07-09 06:45:32 +02:00
run_and_save_command "echo 1 > $file"
2003-08-08 22:55:06 +02:00
else
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Cannot set ARP filtering on $interface"
fi
done
2005-09-19 16:17:29 +02:00
2005-07-26 01:08:09 +02:00
for interface in $interfaces1; do
file=/proc/sys/net/ipv4/conf/$interface/arp_ignore
if [ -f $file ]; then
eval command="\"echo \$$(chain_base $interface)_arp_ignore > $file\""
run_and_save_command "$command"
else
error_message \
"WARNING: Cannot set ARP filtering on $interface"
2003-08-08 22:55:06 +02:00
fi
done
fi
2002-10-23 18:48:40 +02:00
#
2002-06-19 23:51:36 +02:00
# Route Filtering
#
2005-07-09 06:45:32 +02:00
interfaces="$(find_interfaces_by_option routefilter)"
2002-05-01 01:13:15 +02:00
if [ -n "$interfaces" -o -n "$ROUTE_FILTER" ]; then
echo "Setting up Kernel Route Filtering..."
2005-07-09 06:45:32 +02:00
save_progress_message "Restoring Route Filtering..."
2005-07-09 07:45:05 +02:00
for f in /proc/sys/net/ipv4/conf/*; do
run_and_save_command "[ -f $f/rp_filter ] && echo 0 > $f/rp_filter"
2003-10-30 16:42:45 +01:00
done
for interface in $interfaces; do
file=/proc/sys/net/ipv4/conf/$interface/rp_filter
if [ -f $file ]; then
2005-07-09 06:45:32 +02:00
run_and_save_command "echo 1 > $file"
2003-10-30 16:42:45 +01:00
else
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Cannot set route filtering on $interface"
2003-10-30 16:42:45 +01:00
fi
done
2005-09-19 16:17:29 +02:00
2005-07-09 06:45:32 +02:00
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter"
if [ -n "$ROUTE_FILTER" ]; then
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter"
2005-07-09 07:45:05 +02:00
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter"
2005-07-09 06:45:32 +02:00
fi
2005-09-15 01:01:13 +02:00
run_and_save_command "[ -n \"\$NOROUTES\" ] || ip route flush cache"
2005-07-09 06:45:32 +02:00
fi
2005-07-09 07:45:05 +02:00
#
# Martian Logging
#
interfaces="$(find_interfaces_by_option logmartians)"
if [ -n "$interfaces" -o -n "$LOG_MARTIANS" ]; then
echo "Setting up Martian Logging..."
save_progress_message "Restoring Martian Logging..."
for f in /proc/sys/net/ipv4/conf/*; do
run_and_save_command "[ -f $f/log_martians ] && echo 0 > $f/log_martians"
done
for interface in $interfaces; do
file=/proc/sys/net/ipv4/conf/$interface/log_martians
if [ -f $file ]; then
run_and_save_command "echo 1 > $file"
else
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Cannot set Martian logging on $interface"
2005-07-09 07:45:05 +02:00
fi
done
if [ -n "$LOG_MARTIANS" ]; then
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/default/log_martians"
run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/all/log_martians"
fi
fi
#
# Source Routing
#
save_progress_message "Restoring Accept Source Routing..."
for f in /proc/sys/net/ipv4/conf/*; do
run_and_save_command "[ -f $f/accept_source_route ] && echo 0 > $f/accept_source_route"
done
interfaces=$(find_interfaces_by_option sourceroute)
if [ -n "$interfaces" ]; then
echo "Setting up Accept Source Routing..."
2005-09-19 16:17:29 +02:00
2005-07-09 07:45:05 +02:00
for interface in $interfaces; do
file=/proc/sys/net/ipv4/conf/$interface/accept_source_route
if [ -f $file ]; then
run_and_save_command "echo 1 > $file"
else
error_message \
2005-07-26 01:08:09 +02:00
"WARNING: Cannot set Accept Source Routing on $interface"
2005-07-09 07:45:05 +02:00
fi
done
fi
2005-07-09 06:45:32 +02:00
if [ -n "$DYNAMIC_ZONES" ]; then
echo "Setting up Dynamic Zone Chains..."
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
for chain in $(dynamic_chains $interface); do
createchain $chain no
done
chain=$(dynamic_in $interface)
createnatchain $chain
run_iptables -A $(input_chain $interface) -j $chain
run_iptables -A $(forward_chain $interface) -j $(dynamic_fwd $interface)
run_iptables -A OUTPUT -o $interface -j $(dynamic_out $interface)
done
2002-05-01 01:13:15 +02:00
fi
2005-07-09 07:45:05 +02:00
#
# UPnP
#
interfaces=$(find_interfaces_by_option upnp)
if [ -n "$interfaces" ]; then
echo "Setting up UPnP..."
createnatchain UPnP
2005-09-18 00:37:32 +02:00
2005-07-09 07:45:05 +02:00
for interface in $interfaces; do
run_iptables -t nat -A PREROUTING -i $interface -j UPnP
done
fi
2003-11-27 19:24:57 +01:00
setup_forwarding
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Scan the policy file defining the necessary chains
# Add the appropriate policy rule(s) to the end of each canonical chain
#
2002-05-01 01:13:15 +02:00
apply_policy_rules() {
2002-10-23 18:48:40 +02:00
#
2002-06-19 23:51:36 +02:00
# Create policy chains
#
2005-08-17 23:54:57 +02:00
for chain in $ALL_POLICY_CHAINS; do
2002-12-07 04:21:32 +01:00
eval policy=\$${chain}_policy
eval loglevel=\$${chain}_loglevel
2005-08-18 22:18:08 +02:00
eval optional=\$${chain}_is_optional
2002-05-01 01:13:15 +02:00
2005-08-27 00:23:56 +02:00
if ! havechain $chain && [ -z "$optional" -a "$policy" != CONTINUE ]; then
2002-05-01 01:13:15 +02:00
#
2002-11-11 04:41:42 +01:00
# The chain doesn't exist. Create the chain and add policy
2002-06-01 02:28:18 +02:00
# rules
2002-05-31 16:33:18 +02:00
#
2003-02-08 21:58:44 +01:00
createchain $chain yes
2002-11-11 04:41:42 +01:00
#
# If either client or server is 'all' then this MUST be
# a policy chain and we must apply the appropriate policy rules
#
# Otherwise, this is a canonical chain which will be handled in
# the for loop below
#
2005-07-26 01:08:09 +02:00
case $chain in
all2*|*2all)
2005-08-26 19:16:09 +02:00
policy_rules $chain $policy $loglevel
2005-07-26 01:08:09 +02:00
;;
esac
2002-05-01 01:13:15 +02:00
fi
2002-12-07 04:21:32 +01:00
done
2003-02-20 00:52:03 +01:00
2002-10-23 18:48:40 +02:00
#
2002-06-19 23:51:36 +02:00
# Add policy rules to canonical chains
#
2005-07-26 01:08:09 +02:00
for zone in $FW $ZONES; do
for zone1 in $FW $ZONES; do
2002-05-01 01:13:15 +02:00
chain=${zone}2${zone1}
if havechain $chain; then
run_user_exit $chain
default_policy $zone $zone1
fi
done
done
}
2002-10-23 18:48:40 +02:00
#
# Activate the rules
2005-08-02 18:46:30 +02:00
#
2003-02-23 15:10:37 +01:00
activate_rules()
2002-07-05 17:56:02 +02:00
{
2002-07-05 23:57:37 +02:00
local PREROUTING_rule=1
local POSTROUTING_rule=1
2002-10-23 18:48:40 +02:00
#
2002-07-05 23:57:37 +02:00
# Jump to a NAT chain from one of the builtin nat chains
#
addnatjump() # $1 = BUILTIN chain, $2 = user chain, $3 - * other arguments
{
local sourcechain=$1 destchain=$2
shift
shift
2003-02-23 15:10:37 +01:00
2005-07-09 06:45:32 +02:00
if havenatchain $destchain ; then
2005-07-09 07:45:05 +02:00
run_iptables2 -t nat -A $sourcechain $@ -j $destchain
else
[ -n "$BRIDGING" -a -f $TMP_DIR/physdev ] && -rm -f $TMP_DIR/physdev
[ -n "$IPRANGE_MATCH" -a -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
2005-07-09 06:45:32 +02:00
fi
2002-07-05 23:57:37 +02:00
}
2003-02-23 15:10:37 +01:00
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Jump to a RULES chain from one of the builtin nat chains. These jumps are
2005-07-09 07:45:05 +02:00
# are inserted before jumps to one-to-one NAT chains.
2002-07-05 23:57:37 +02:00
#
addrulejump() # $1 = BUILTIN chain, $2 = user chain, $3 - * other arguments
{
local sourcechain=$1 destchain=$2
shift
shift
2003-02-23 15:10:37 +01:00
2002-07-05 23:57:37 +02:00
if havenatchain $destchain; then
2005-07-09 07:45:05 +02:00
eval run_iptables2 -t nat -I $sourcechain \
2005-07-09 06:45:32 +02:00
\$${sourcechain}_rule $@ -j $destchain
eval ${sourcechain}_rule=\$\(\(\$${sourcechain}_rule + 1\)\)
2005-08-02 18:46:30 +02:00
else
2005-07-09 07:45:05 +02:00
[ -n "$BRIDGING" -a -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
[ -n "$IPRANGE_MATCH" -a -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
2002-07-05 17:56:02 +02:00
fi
2005-08-02 18:46:30 +02:00
}
2002-06-30 16:35:32 +02:00
2005-08-02 18:46:30 +02:00
#
2005-07-27 19:29:20 +02:00
# Create a dynamic chain for a zone and jump to it from a second chain
#
create_zone_dyn_chain() # $1 = zone, $2 = second chain
{
createchain ${1}_dyn No
run_iptables -A $2 -j ${1}_dyn
}
2005-07-09 07:45:05 +02:00
#
# Add jumps to early SNAT chains
#
for interface in $ALL_INTERFACES; do
addnatjump POSTROUTING $(snat_chain $interface) -o $interface
done
2005-07-09 06:45:32 +02:00
#
# Add jumps for dynamic nat chains
#
2005-07-09 07:45:05 +02:00
[ -n "$DYNAMIC_ZONES" ] && for interface in $ALL_INTERFACES ; do
2005-07-09 06:45:32 +02:00
addrulejump PREROUTING $(dynamic_in $interface) -i $interface
done
2002-07-05 23:57:37 +02:00
#
# Add jumps from the builtin chains to the nat chains
#
2002-07-05 17:56:02 +02:00
addnatjump PREROUTING nat_in
addnatjump POSTROUTING nat_out
2002-05-30 14:55:47 +02:00
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES; do
2005-07-09 06:45:32 +02:00
addnatjump PREROUTING $(input_chain $interface) -i $interface
addnatjump POSTROUTING $(output_chain $interface) -o $interface
2002-07-04 17:41:51 +02:00
done
2005-07-26 01:08:09 +02:00
> /var/lib/shorewall/chains
2005-10-04 16:54:56 +02:00
echo "$FW firewall" > /var/lib/shorewall/zones
2005-07-09 07:45:05 +02:00
#
# Create forwarding chains for complex zones and generate jumps for IPSEC source hosts to that chain.
#
2005-07-26 01:08:09 +02:00
for zone in $ZONES; do
2005-07-09 07:45:05 +02:00
if eval test -n \"\$${zone}_is_complex\" ; then
frwd_chain=${zone}_frwd
createchain $frwd_chain No
if [ -n "$POLICY_MATCH" ]; then
2005-07-26 01:08:09 +02:00
#
# Because policy match only matches an 'in' or an 'out' policy (but not both), we have to place the
# '--pol ipsec --dir in' rules at the front of the interface forwarding chains. Otherwise, decrypted packets
# can match '--pol none --dir out' rules and send the packets down the wrong rules chain.
#
2005-07-09 07:45:05 +02:00
eval is_ipsec=\$${zone}_is_ipsec
if [ -n "$is_ipsec" ]; then
eval source_hosts=\$${zone}_hosts
2005-07-27 19:29:20 +02:00
[ -n "$DYNAMIC_ZONES" ] && create_zone_dyn_chain $zone $frwd_chain
2005-07-09 07:45:05 +02:00
else
eval source_hosts=\$${zone}_ipsec_hosts
2005-07-27 19:29:20 +02:00
[ -n "$DYNAMIC_ZONES" -a -n "$source_hosts" ] && create_zone_dyn_chain $zone $frwd_chain
2005-07-09 07:45:05 +02:00
fi
for host in $source_hosts; do
interface=${host%%:*}
networks=${host#*:}
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
run_iptables2 -A $(forward_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $frwd_chain
done
fi
fi
done
2005-07-26 01:08:09 +02:00
for zone in $ZONES; do
2002-05-01 01:13:15 +02:00
eval source_hosts=\$${zone}_hosts
2005-07-09 06:45:32 +02:00
chain1=$(rules_chain $FW $zone)
chain2=$(rules_chain $zone $FW)
2002-10-01 22:54:42 +02:00
2003-10-15 20:34:05 +02:00
eval complex=\$${zone}_is_complex
2005-10-04 16:54:56 +02:00
eval type=\$${zone}_type
2003-10-15 20:34:05 +02:00
2005-07-09 07:45:05 +02:00
[ -n "$complex" ] && frwd_chain=${zone}_frwd
2003-10-15 20:34:05 +02:00
2005-10-04 16:54:56 +02:00
echo $zone $type $source_hosts >> /var/lib/shorewall/zones
2005-07-26 01:08:09 +02:00
2005-07-09 06:45:32 +02:00
if [ -n "$DYNAMIC_ZONES" ]; then
2005-07-26 01:08:09 +02:00
echo "$FW $zone $chain1" >> /var/lib/shorewall/chains
echo "$zone $FW $chain2" >> /var/lib/shorewall/chains
2005-07-09 06:45:32 +02:00
fi
2003-02-23 15:10:37 +01:00
2004-01-24 00:48:30 +01:00
need_broadcast=
2002-05-01 01:13:15 +02:00
for host in $source_hosts; do
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
networks=${host#*:}
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
[ -n "$chain1" ] && run_iptables2 -A OUTPUT -o $interface $(match_dest_hosts $networks) $(match_ipsec_out $zone $host) -j $chain1
2002-10-01 22:54:42 +02:00
2002-07-05 23:57:37 +02:00
#
2005-08-02 23:06:05 +02:00
# Add jumps from the builtin chain for DNAT rules
2002-07-05 23:57:37 +02:00
#
2005-07-09 07:45:05 +02:00
addrulejump PREROUTING $(dnat_chain $zone) -i $interface $(match_source_hosts $networks) $(match_ipsec_in $zone $host)
2002-05-18 21:04:45 +02:00
2005-07-26 01:08:09 +02:00
[ -n "$chain2" ] && run_iptables2 -A $(input_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $chain2
2003-10-15 20:34:05 +02:00
2005-07-09 07:45:05 +02:00
if [ -n "$complex" ] && ! is_ipsec_host $zone $host ; then
run_iptables2 -A $(forward_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $frwd_chain
fi
2003-10-15 20:34:05 +02:00
2005-07-09 06:45:32 +02:00
case $networks in
2005-07-09 07:55:29 +02:00
*.*.*.*|+*)
2005-07-09 06:45:32 +02:00
if [ "$networks" != 0.0.0.0/0 ]; then
if ! list_search $interface $need_broadcast ; then
interface_has_option $interface detectnets && need_broadcast="$need_broadcast $interface"
fi
fi
;;
esac
2002-05-01 01:13:15 +02:00
done
2005-07-26 01:08:09 +02:00
if [ -n "$chain1" ]; then
for interface in $need_broadcast ; do
run_iptables -A OUTPUT -o $interface -d 255.255.255.255 -j $chain1
run_iptables -A OUTPUT -o $interface -d 224.0.0.0/4 -j $chain1
done
fi
for zone1 in $ZONES; do
2002-05-01 01:13:15 +02:00
2003-03-21 05:14:20 +01:00
eval policy=\$${zone}2${zone1}_policy
2002-05-01 01:13:15 +02:00
2003-03-21 05:14:20 +01:00
[ "$policy" = NONE ] && continue
2003-03-24 22:56:31 +01:00
2003-03-21 05:14:20 +01:00
eval dest_hosts=\$${zone1}_hosts
2002-10-01 22:54:42 +02:00
2005-07-09 06:45:32 +02:00
chain="$(rules_chain $zone $zone1)"
2002-09-15 00:00:52 +02:00
2005-07-26 01:08:09 +02:00
[ -z "$chain" ] && continue # CONTINUE policy and there is no canonical chain.
[ -n "$DYNAMIC_ZONES" ] && echo "$zone $zone1 $chain" >> /var/lib/shorewall/chains
2003-03-21 05:14:20 +01:00
2003-04-01 04:00:37 +02:00
if [ $zone = $zone1 ]; then
2005-07-09 06:45:32 +02:00
#
# Try not to generate superfluous intra-zone rules
#
2003-04-01 04:00:37 +02:00
eval routeback=\"\$${zone}_routeback\"
2005-07-09 06:45:32 +02:00
eval interfaces=\"\$${zone}_interfaces\"
eval ports="\$${zone}_ports"
num_ifaces=$(list_count1 $interfaces)
#
# If the zone has a single interface then what matters is how many ports it has
#
[ $num_ifaces -eq 1 -a -n "$ports" ] && num_ifaces=$(list_count1 $ports)
#
# If we don't need to route back and if we have only one interface or one port to
# the zone then assume that hosts in the zone can communicate directly.
#
if [ $num_ifaces -lt 2 -a -z "$routeback" ] ; then
continue
fi
2003-04-01 04:00:37 +02:00
else
routeback=
2005-07-09 06:45:32 +02:00
num_ifaces=0
2003-04-01 04:00:37 +02:00
fi
2005-09-18 00:37:32 +02:00
2003-10-15 20:34:05 +02:00
if [ -n "$complex" ]; then
2002-05-01 01:13:15 +02:00
for host1 in $dest_hosts; do
2005-07-09 06:45:32 +02:00
interface1=${host1%%:*}
networks1=${host1#*:}
#
# Only generate an intrazone rule if the zone has more than one interface (port) or if
# routeback was specified for this host group
#
if [ $zone != $zone1 -o $num_ifaces -gt 1 ] || list_search $host1 $routeback ; then
2005-09-19 16:43:22 +02:00
run_iptables2 -A $frwd_chain -o $interface1 $(match_dest_hosts $networks1) $(match_ipsec_out $zone1 $host1) -j $chain
2002-05-30 14:55:47 +02:00
fi
2002-05-01 01:13:15 +02:00
done
2003-10-15 20:34:05 +02:00
else
for host in $source_hosts; do
2005-07-09 06:45:32 +02:00
interface=${host%%:*}
networks=${host#*:}
2005-09-19 16:43:22 +02:00
2005-07-26 01:08:09 +02:00
chain3=$(forward_chain $interface)
2005-09-18 00:37:32 +02:00
2003-10-15 20:34:05 +02:00
for host1 in $dest_hosts; do
2005-07-09 06:45:32 +02:00
interface1=${host1%%:*}
networks1=${host1#*:}
2003-10-15 20:34:05 +02:00
if [ "$host" != "$host1" ] || list_search $host $routeback; then
2005-07-26 01:08:09 +02:00
run_iptables2 -A $chain3 $(match_source_hosts $networks) -o $interface1 $(match_dest_hosts $networks1) $(match_ipsec_out $zone1 $host1) -j $chain
2003-10-15 20:34:05 +02:00
fi
done
done
fi
2002-05-01 01:13:15 +02:00
done
done
2005-07-09 07:55:29 +02:00
2005-07-09 07:45:05 +02:00
for interface in $ALL_INTERFACES ; do
2005-07-09 06:45:32 +02:00
run_iptables -A FORWARD -i $interface -j $(forward_chain $interface)
run_iptables -A INPUT -i $interface -j $(input_chain $interface)
addnatjump POSTROUTING $(masq_chain $interface) -o $interface
#
# Bridges under the 2.4 kernel have the wierd property that REJECTS have the physdev-in and physdev-out set to the input physdev.
# To accomodate this feature/bug, we effectively set 'routeback' on bridge ports.
#
eval ports=\$$(chain_base $interface)_ports
for port in $ports; do
run_iptables -A $(forward_chain $interface) -o $interface -m physdev --physdev-in $port --physdev-out $port -j ACCEPT
done
2002-05-18 15:45:23 +02:00
done
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
chain=${FW}2${FW}
if havechain $chain; then
#
# There is a fw->fw chain. Send loopback output through that chain
#
run_ip link ls | grep LOOPBACK | while read ordinal interface rest ; do
run_iptables -A OUTPUT -o ${interface%:*} -j $chain
done
#
# And delete the unconditional ACCEPT rule
#
run_iptables -D OUTPUT -o lo -j ACCEPT
fi
2002-05-01 01:13:15 +02:00
complete_standard_chain INPUT all $FW
complete_standard_chain OUTPUT $FW all
complete_standard_chain FORWARD all all
2003-06-11 03:01:48 +02:00
#
# Remove rules added to keep the firewall alive during [re]start"
#
2005-07-26 01:08:09 +02:00
disable_critical_hosts
2003-03-08 16:48:07 +01:00
for chain in INPUT OUTPUT FORWARD; do
2005-08-11 21:53:07 +02:00
[ -n "$FASTACCEPT" ] || run_iptables -D $chain -m state --state ESTABLISHED,RELATED -j ACCEPT
2003-03-08 16:48:07 +01:00
run_iptables -D $chain -p udp --dport 53 -j ACCEPT
done
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
process_routestopped -D
if [ -n "$LOGALLNEW" ]; then
for table in mangle nat filter; do
case $table in
mangle)
chains="PREROUTING INPUT FORWARD POSTROUTING"
;;
nat)
chains="PREROUTING POSTROUTING OUTPUT"
;;
*)
chains="INPUT FORWARD OUTPUT"
;;
esac
for chain in $chains; do
log_rule_limit $LOGALLNEW $chain $table $chain "" "" -I -m state --state NEW -t $table
done
done
fi
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
2003-07-28 19:32:41 +02:00
# Check for disabled startup
2002-10-23 18:48:40 +02:00
#
2003-07-28 19:32:41 +02:00
check_disabled_startup() {
2005-07-09 07:45:05 +02:00
if [ -z "$STARTUP_ENABLED" ]; then
2002-09-19 22:40:10 +02:00
echo " Shorewall Startup is disabled -- to enable startup"
echo " after you have completed Shorewall configuration,"
2005-07-09 07:45:05 +02:00
echo " change the setting of STARTUP_ENABLED to Yes in"
echo " /etc/shorewall/shorewall.conf"
2002-09-19 22:40:10 +02:00
2002-09-29 23:28:44 +02:00
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
2002-09-19 22:40:10 +02:00
my_mutex_off
exit 2
fi
2003-07-28 19:32:41 +02:00
}
#
# Start/Restart the Firewall
#
define_firewall() # $1 = Command (Start or Restart)
{
check_disabled_startup
2002-09-19 22:40:10 +02:00
2002-05-01 01:13:15 +02:00
echo "${1}ing Shorewall..."
2005-07-29 20:32:50 +02:00
set_state "${1}ing"
2002-05-01 01:13:15 +02:00
verify_os_version
2003-02-21 23:55:36 +01:00
verify_ip
2005-07-09 06:45:32 +02:00
[ -d /var/lib/shorewall ] || { mkdir -p /var/lib/shorewall ; chmod 700 /var/lib/shorewall; }
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
RESTOREBASE=$(mktempfile /var/lib/shorewall)
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
[ -n "$RESTOREBASE" ] || startup_error "Cannot create temporary file in /var/lib/shorewall"
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
echo '#bin/sh' >> $RESTOREBASE
save_command "#"
save_command "# Restore base file generated by Shorewall $version - $(date)"
save_command "#"
save_command ". /usr/share/shorewall/functions"
2002-05-01 01:13:15 +02:00
2005-07-09 07:45:05 +02:00
f=$(find_file params)
[ -f $f ] && \
2005-09-09 18:52:10 +02:00
save_command ". $(resolve_file $f)"
2005-07-09 07:45:05 +02:00
save_command "#"
2005-08-17 19:52:32 +02:00
save_command "COMMAND=restore"
2005-07-09 06:45:32 +02:00
save_command "MODULESDIR=\"$MODULESDIR\""
save_command "MODULE_SUFFIX=\"$MODULE_SUFFIX\""
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
save_load_kernel_modules
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
echo "Initializing..."; initialize_netfilter
2005-07-09 07:55:29 +02:00
2005-07-09 06:45:32 +02:00
echo "Configuring Proxy ARP"; setup_proxy_arp
2005-07-09 07:55:29 +02:00
#
# [re]-Establish routing
#
setup_providers $(find_file providers)
2005-07-26 01:08:09 +02:00
[ -n "$ROUTEMARK_INTERFACES" ] && setup_routes
2005-07-09 07:55:29 +02:00
2005-07-09 06:45:32 +02:00
echo "Setting up NAT..."; setup_nat
echo "Setting up NETMAP..."; setup_netmap
echo "Adding Common Rules"; add_common_rules
2002-05-01 01:13:15 +02:00
2005-08-27 00:23:56 +02:00
setup_syn_flood_chains
2005-07-26 01:08:09 +02:00
setup_ipsec
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
maclist_hosts=$(find_hosts_by_option maclist)
[ -n "$maclist_hosts" ] && setup_mac_lists
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
echo "Processing $(find_file rules)..."; process_rules
2005-08-27 16:50:33 +02:00
tunnels=$(find_file tunnels)
[ -f $tunnels ] && \
echo "Processing $tunnels..." && setup_tunnels $tunnels
2005-07-09 06:45:32 +02:00
echo "Processing Actions..."; process_actions2
2005-07-09 07:45:05 +02:00
process_actions3
2005-07-09 06:45:32 +02:00
echo "Processing $(find_file policy)..."; apply_policy_rules
2003-12-04 03:01:08 +01:00
2005-07-09 06:45:32 +02:00
masq=$(find_file masq)
[ -f $masq ] && setup_masq $masq
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
tos=$(find_file tos)
2002-05-01 01:13:15 +02:00
[ -f $tos ] && [ -n "$MANGLE_ENABLED" ] && process_tos $tos
2005-07-09 06:45:32 +02:00
ecn=$(find_file ecn)
2003-03-24 22:56:31 +01:00
[ -f $ecn ] && [ -n "$MANGLE_ENABLED" ] && setup_ecn $ecn
2003-02-24 16:24:55 +01:00
2005-10-06 16:21:04 +02:00
[ -n "$MANGLE_ENABLED" ] && setup_tc
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
echo "Activating Rules..."; activate_rules
2002-05-01 01:13:15 +02:00
2005-08-23 22:41:18 +02:00
[ -n "$ALIASES_TO_ADD" ] && \
2005-07-09 06:45:32 +02:00
echo "Adding IP Addresses..." && add_ip_aliases
2002-07-23 18:26:45 +02:00
2005-07-09 06:45:32 +02:00
for file in chains nat proxyarp zones; do
append_file $file
done
2005-07-09 07:55:29 +02:00
2005-07-09 06:45:32 +02:00
save_progress_message "Restoring Netfilter Configuration..."
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
save_command 'iptables-restore << __EOF__'
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
# 'shorewall save' appends the iptables-save output and '__EOF__'
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
mv -f $RESTOREBASE /var/lib/shorewall/restore-base-$$
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
> $RESTOREBASE
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
save_command "#"
save_command "# Restore tail file generated by Shorewall $version - $(date)"
save_command "#"
2005-07-26 01:08:09 +02:00
save_command "date > /var/lib/shorewall/restarted"
2005-07-09 07:45:05 +02:00
2002-05-01 01:13:15 +02:00
run_user_exit start
2005-07-09 07:45:05 +02:00
[ -n "$DELAYBLACKLISTLOAD" ] && refresh_blacklist
2002-05-01 01:13:15 +02:00
createchain shorewall no
2005-07-26 01:08:09 +02:00
date > /var/lib/shorewall/restarted
2002-07-23 00:31:07 +02:00
2005-07-29 20:32:50 +02:00
run_and_save_command set_state "Started"
2002-05-03 00:56:27 +02:00
report "Shorewall ${1}ed"
2002-05-01 01:13:15 +02:00
2005-07-24 18:27:21 +02:00
run_user_exit started
2002-05-01 01:13:15 +02:00
rm -rf $TMP_DIR
2005-07-09 06:45:32 +02:00
mv -f /var/lib/shorewall/restore-base-$$ /var/lib/shorewall/restore-base
2005-08-02 18:46:30 +02:00
mv -f $RESTOREBASE /var/lib/shorewall/restore-tail
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Refresh the firewall
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
refresh_firewall()
{
echo "Refreshing Shorewall..."
echo "Determining Zones and Interfaces..."
determine_zones
2002-12-04 22:17:14 +01:00
validate_interfaces_file
2002-05-01 01:13:15 +02:00
determine_interfaces
2002-05-30 14:55:47 +02:00
run_user_exit refresh
2002-10-23 18:48:40 +02:00
#
2002-05-01 01:13:15 +02:00
# Blacklist
#
refresh_blacklist
2005-07-09 06:45:32 +02:00
ecn=$(find_file ecn)
2003-02-24 16:24:55 +01:00
2003-03-24 22:56:31 +01:00
[ -f $ecn ] && [ -n "$MANGLE_ENABLED" ] && setup_ecn $ecn
2002-12-04 22:17:14 +01:00
#
# Refresh Traffic Control
#
2005-10-06 16:21:04 +02:00
[ -n "$MANGLE_ENABLED" ] && refresh_tc
2002-12-04 22:17:14 +01:00
2002-05-03 00:56:27 +02:00
report "Shorewall Refreshed"
2002-05-01 01:13:15 +02:00
rm -rf $TMP_DIR
}
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Add a host or networks to a zone
2002-10-23 18:48:40 +02:00
#
2005-07-09 07:45:05 +02:00
add_to_zone() # $1...${n-1} = <interface>[:<hosts>] $n = zone
2002-10-01 22:54:42 +02:00
{
2005-07-09 07:45:05 +02:00
local interface host zone z h z1 z2 chain
2005-07-09 07:55:29 +02:00
local dhcp_interfaces blacklist_interfaces maclist_interfaces
local tcpflags_interfaces newhostlist=
2005-07-09 07:45:05 +02:00
local rulenum source_chain dest_hosts iface hosts hostlist=
2002-10-02 00:27:19 +02:00
2002-10-01 22:54:42 +02:00
nat_chain_exists() # $1 = chain name
{
2005-07-09 07:45:05 +02:00
qt $IPTABLES -t nat -L $1 -n
2002-10-01 22:54:42 +02:00
}
do_iptables() # $@ = command
{
2005-07-09 06:45:32 +02:00
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
2005-07-09 07:45:05 +02:00
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
if ! $IPTABLES $@ ; then
error_message "Can't add $newhost to zone $zone"
2002-10-01 22:54:42 +02:00
fi
}
2002-10-02 03:24:57 +02:00
#
# Load $zones
#
2002-10-01 22:54:42 +02:00
determine_zones
2002-10-02 03:24:57 +02:00
#
2005-07-09 06:45:32 +02:00
# Validate Interfaces File
#
validate_interfaces_file
#
2005-07-09 07:45:05 +02:00
# Validate Hosts File
#
validate_hosts_file
#
# Validate IPSec File
#
f=$(find_file ipsec)
[ -f $f ] && setup_ipsec $f
#
# Normalize host list
#
while [ $# -gt 1 ]; do
interface=${1%%:*}
host=${1#*:}
#
# Be sure that the interface was dynamic at last [re]start
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
fi
if [ -z "$host" ]; then
hostlist="$hostlist $interface:0.0.0.0/0"
else
for h in $(separate_list $host); do
hostlist="$hostlist $interface:$h"
done
fi
shift
done
#
2002-10-02 03:24:57 +02:00
# Validate Zone
#
2005-07-09 07:45:05 +02:00
zone=$1
2002-10-01 22:54:42 +02:00
2003-02-08 21:58:44 +01:00
validate_zone $zone || startup_error "Unknown zone: $zone"
2002-10-01 22:54:42 +02:00
2003-02-08 21:58:44 +01:00
[ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone"
2005-07-09 07:45:05 +02:00
2002-10-02 03:24:57 +02:00
#
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
#
2005-07-26 01:08:09 +02:00
[ -f /var/lib/shorewall/chains ] || startup_error "/var/lib/shorewall/chains -- file not found"
[ -f /var/lib/shorewall/zones ] || startup_error "/var/lib/shorewall/zones -- file not found"
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
# Check for duplicates and create a new zone state file
2002-10-02 03:24:57 +02:00
#
2005-07-26 01:08:09 +02:00
> /var/lib/shorewall/zones_$$
2005-07-09 07:45:05 +02:00
2005-10-04 16:54:56 +02:00
while read z type hosts; do
2002-10-01 22:54:42 +02:00
if [ "$z" = "$zone" ]; then
2005-07-09 07:55:29 +02:00
for h in $hostlist; do
list_search $h $hosts
if [ "$?" -gt 0 ]; then
newhostlist="$newhostlist $h"
else
error_message "$h already in zone $zone"
fi
2002-10-01 22:54:42 +02:00
done
2005-09-19 16:43:22 +02:00
2005-07-09 07:55:29 +02:00
[ -z "$hosts" ] && hosts=$newhostlist || hosts="$hosts $newhostlist"
2002-10-01 22:54:42 +02:00
fi
2002-10-01 23:46:48 +02:00
eval ${z}_hosts=\"$hosts\"
2005-09-19 16:43:22 +02:00
2005-10-04 16:54:56 +02:00
echo "$z $type $hosts" >> /var/lib/shorewall/zones_$$
2005-07-26 01:08:09 +02:00
done < /var/lib/shorewall/zones
2002-10-01 22:54:42 +02:00
2005-07-26 01:08:09 +02:00
mv -f /var/lib/shorewall/zones_$$ /var/lib/shorewall/zones
2002-10-01 22:54:42 +02:00
2005-08-01 19:17:24 +02:00
TERMINATOR=fatal_error
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
# Create a new Zone state file
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:55:29 +02:00
for newhost in $newhostlist; do
2005-07-09 07:45:05 +02:00
#
# Isolate interface and host parts
#
interface=${newhost%%:*}
host=${newhost#*:}
#
# If the zone passed in the command has a dnat chain then insert a rule in
# the nat table PREROUTING chain to jump to that chain when the source
# matches the new host(s)#
#
chain=${zone}_dnat
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
if nat_chain_exists $chain; then
do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $(match_ipsec_in $zone $newhost) -j $chain
fi
#
# Insert new rules into the filter table for the passed interface
#
while read z1 z2 chain; do
2005-07-09 07:55:29 +02:00
[ "$z1" = "$z2" ] && op="-I" || op="-A"
2005-07-09 07:45:05 +02:00
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
2005-07-09 07:55:29 +02:00
do_iptables $op $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
2005-07-09 07:45:05 +02:00
else
source_chain=$(dynamic_fwd $interface)
if is_ipsec_host $z1 $newhost ; then
2005-07-09 07:55:29 +02:00
do_iptables $op $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
2005-07-09 07:45:05 +02:00
else
eval dest_hosts=\"\$${z2}_hosts\"
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
for h in $dest_hosts; do
iface=${h%%:*}
hosts=${h#*:}
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
2005-07-09 07:55:29 +02:00
do_iptables $op $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
2005-07-09 07:45:05 +02:00
fi
done
2002-10-01 23:46:48 +02:00
fi
2005-07-09 07:45:05 +02:00
fi
elif [ "$z2" = "$zone" ]; then
if [ "$z1" = "$FW" ]; then
#
# Add a rule to the dynamic out chain for the interface
#
2005-07-09 07:55:29 +02:00
do_iptables $op $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
2005-07-09 07:45:05 +02:00
else
eval source_hosts=\"\$${z1}_hosts\"
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
for h in $source_hosts; do
iface=${h%%:*}
hosts=${h#*:}
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
if is_ipsec_host $z1 $h; then
2005-07-09 07:55:29 +02:00
do_iptables $op ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
2005-07-09 07:45:05 +02:00
else
2005-07-09 07:55:29 +02:00
do_iptables $op $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
2005-07-09 07:45:05 +02:00
fi
fi
done
fi
2002-10-01 22:54:42 +02:00
fi
2005-07-26 01:08:09 +02:00
done < /var/lib/shorewall/chains
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
progress_message "$newhost added to zone $zone"
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
done
2002-10-01 22:54:42 +02:00
2003-04-18 05:09:51 +02:00
rm -rf $TMP_DIR
2003-02-23 15:10:37 +01:00
}
2002-10-01 22:54:42 +02:00
2002-10-23 18:48:40 +02:00
#
2005-07-09 06:45:32 +02:00
# Delete a host or networks from a zone
2002-10-23 18:48:40 +02:00
#
2002-10-01 22:54:42 +02:00
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
{
2005-07-09 07:45:05 +02:00
local interface host zone z h z1 z2 chain delhost
local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
local rulenum source_chain dest_hosts iface hosts hostlist=
2005-08-02 18:46:30 +02:00
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
# Load $zones
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
determine_zones
#
# Validate Interfaces File
#
validate_interfaces_file
#
# Validate Hosts File
#
validate_hosts_file
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
# Validate IPSec File
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
f=$(find_file ipsec)
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
[ -f $f ] && setup_ipsec $f
2002-10-01 22:54:42 +02:00
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
# Normalize host list
2002-10-02 03:24:57 +02:00
#
2005-07-09 07:45:05 +02:00
while [ $# -gt 1 ]; do
interface=${1%%:*}
host=${1#*:}
#
# Be sure that the interface was dynamic at last [re]start
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
fi
if [ -z "$host" ]; then
hostlist="$hostlist $interface:0.0.0.0/0"
else
for h in $(separate_list $host); do
hostlist="$hostlist $interface:$h"
done
fi
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
shift
done
#
# Validate Zone
#
zone=$1
2002-10-01 22:54:42 +02:00
2003-02-08 21:58:44 +01:00
validate_zone $zone || startup_error "Unknown zone: $zone"
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
[ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
2002-10-02 03:24:57 +02:00
#
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
#
2005-07-26 01:08:09 +02:00
[ -f /var/lib/shorewall/chains ] || startup_error "/var/lib/shorewall/chains -- file not found"
[ -f /var/lib/shorewall/zones ] || startup_error "/var/lib/shorewall/zones -- file not found"
2002-10-02 03:24:57 +02:00
#
# Delete the passed hosts from the zone state file
#
2005-07-26 01:08:09 +02:00
> /var/lib/shorewall/zones_$$
2005-07-09 07:45:05 +02:00
2002-10-01 22:54:42 +02:00
while read z hosts; do
2005-07-09 07:45:05 +02:00
if [ "$z" = "$zone" ]; then
temp=$hosts
hosts=
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
for host in $hostlist; do
found=
for h in $temp; do
if [ "$h" = "$host" ]; then
found=Yes
break
fi
done
2005-07-09 07:55:29 +02:00
[ -n "$found" ] || error_message "Warning: $host does not appear to be in zone $zone"
2005-07-09 07:45:05 +02:00
done
for h in $temp; do
found=
for host in $hostlist; do
if [ "$h" = "$host" ]; then
found=Yes
break
fi
done
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
[ -n "$found" ] || hosts="$hosts $h"
done
fi
2002-10-01 23:46:48 +02:00
eval ${z}_hosts=\"$hosts\"
2005-07-09 07:45:05 +02:00
2005-07-26 01:08:09 +02:00
echo "$z $hosts" >> /var/lib/shorewall/zones_$$
done < /var/lib/shorewall/zones
2003-02-23 15:22:14 +01:00
2005-07-26 01:08:09 +02:00
mv -f /var/lib/shorewall/zones_$$ /var/lib/shorewall/zones
2005-07-09 07:45:05 +02:00
2005-08-01 19:17:24 +02:00
TERMINATOR=fatal_error
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
for delhost in $hostlist; do
interface=${delhost%%:*}
host=${delhost#*:}
#
# Delete any nat table entries for the host(s)
#
qt_iptables -t nat -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $zone $delhost) -j ${zone}_dnat
#
# Delete rules rules the input chains for the passed interface
#
while read z1 z2 chain; do
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
qt_iptables -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $delhost) -j $chain
else
source_chain=$(dynamic_fwd $interface)
if is_ipsec_host $z1 $delhost ; then
qt_iptables -D $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
else
eval dest_hosts=\"\$${z2}_hosts\"
2003-02-23 15:10:37 +01:00
2005-07-09 07:45:05 +02:00
[ "$z2" = "$zone" ] && dest_hosts="$dest_hosts $hostlist"
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
for h in $dest_hosts; do
iface=${h%%:*}
hosts=${h#*:}
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
qt_iptables -D $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
fi
done
2002-10-01 23:46:48 +02:00
fi
2005-07-09 07:45:05 +02:00
fi
elif [ "$z2" = "$zone" ]; then
if [ "$z1" = "$FW" ]; then
qt_iptables -D $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
else
eval source_hosts=\"\$${z1}_hosts\"
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
for h in $source_hosts; do
iface=${h%%:*}
hosts=${h#*:}
2005-09-19 16:43:22 +02:00
2005-07-09 07:45:05 +02:00
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
if is_ipsec_host $z1 $h; then
qt_iptables -D ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
else
qt_iptables -D $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
fi
fi
done
fi
2002-10-01 22:54:42 +02:00
fi
2005-07-26 01:08:09 +02:00
done < /var/lib/shorewall/chains
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
progress_message "$delhost removed from zone $zone"
2002-10-01 22:54:42 +02:00
2005-07-09 07:45:05 +02:00
done
2005-08-02 18:46:30 +02:00
2003-04-18 05:09:51 +02:00
rm -rf $TMP_DIR
2003-02-23 15:10:37 +01:00
}
2002-10-01 22:54:42 +02:00
2002-10-23 18:48:40 +02:00
#
# Determine the value for a parameter that defaults to Yes
#
2002-05-01 01:13:15 +02:00
added_param_value_yes() # $1 = Parameter Name, $2 = Parameter value
{
local val="$2"
if [ -z "$val" ]; then
echo "Yes"
else case $val in
2002-07-06 00:24:40 +02:00
[Yy][Ee][Ss])
2002-05-01 01:13:15 +02:00
echo "Yes"
;;
[Nn][Oo])
echo ""
;;
*)
startup_error "Invalid value ($val) for $1"
;;
esac
fi
}
2002-10-23 18:48:40 +02:00
#
# Determine the value for a parameter that defaults to No
#
2002-05-01 01:13:15 +02:00
added_param_value_no() # $1 = Parameter Name, $2 = Parameter value
{
local val="$2"
if [ -z "$val" ]; then
echo ""
else case $val in
2002-07-06 00:24:40 +02:00
[Yy][Ee][Ss])
2002-05-01 01:13:15 +02:00
echo "Yes"
;;
[Nn][Oo])
echo ""
;;
*)
startup_error "Invalid value ($val) for $1"
;;
esac
fi
}
2002-10-23 18:48:40 +02:00
#
# Initialize this program
#
2002-05-01 01:13:15 +02:00
do_initialize() {
2005-08-02 18:46:30 +02:00
2002-05-01 01:13:15 +02:00
# Run all utility programs using the C locale
#
# Thanks to Vincent Planchenault for this tip #
export LC_ALL=C
2005-07-09 07:45:05 +02:00
# Make sure umask is sane
umask 177
2002-05-01 01:13:15 +02:00
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
2002-10-23 18:48:40 +02:00
#
2003-02-23 15:10:37 +01:00
# Establish termination function
#
2005-08-01 19:17:24 +02:00
TERMINATOR=startup_error
2003-02-23 15:10:37 +01:00
#
2002-05-01 01:13:15 +02:00
# Clear all configuration variables
#
version=
2005-07-09 07:45:05 +02:00
IPTABLES=
2002-05-01 01:13:15 +02:00
FW=
SUBSYSLOCK=
2003-02-08 21:58:44 +01:00
ALLOWRELATED=Yes
2002-05-01 01:13:15 +02:00
LOGRATE=
LOGBURST=
LOGPARMS=
2003-08-22 17:27:08 +02:00
LOGLIMIT=
2002-05-01 01:13:15 +02:00
ADD_IP_ALIASES=
ADD_SNAT_ALIASES=
TC_ENABLED=
BLACKLIST_DISPOSITION=
BLACKLIST_LOGLEVEL=
CLAMPMSS=
ROUTE_FILTER=
2005-07-09 07:45:05 +02:00
LOG_MARTIANS=
2002-07-09 23:21:28 +02:00
DETECT_DNAT_IPADDRS=
2002-07-24 05:47:34 +02:00
MUTEX_TIMEOUT=
2002-08-12 19:33:05 +02:00
FORWARDPING=
2002-10-22 20:07:52 +02:00
MACLIST_DISPOSITION=
MACLIST_LOG_LEVEL=
2002-11-10 22:34:20 +01:00
TCP_FLAGS_DISPOSITION=
TCP_FLAGS_LOG_LEVEL=
2002-12-13 04:23:46 +01:00
RFC1918_LOG_LEVEL=
2002-12-16 20:25:20 +01:00
MARK_IN_FORWARD_CHAIN=
2003-02-08 21:58:44 +01:00
SHARED_DIR=/usr/share/shorewall
2003-01-07 00:01:23 +01:00
FUNCTIONS=
VERSION_FILE=
2003-05-21 23:36:05 +02:00
LOGFORMAT=
2003-05-27 19:42:12 +02:00
LOGRULENUMBERS=
2003-07-30 01:04:04 +02:00
ADMINISABSENTMINDED=
2003-10-11 18:06:00 +02:00
BLACKLISTNEWONLY=
2003-12-01 17:10:08 +01:00
MODULE_SUFFIX=
2003-12-04 03:01:08 +01:00
ACTIONS=
2005-07-09 06:45:32 +02:00
USEDACTIONS=
SMURF_LOG_LEVEL=
DISABLE_IPV6=
BRIDGING=
DYNAMIC_ZONES=
PKTTYPE=
2005-08-14 21:26:17 +02:00
USEPKTYPE=
2005-07-09 07:45:05 +02:00
RETAIN_ALIASES=
DELAYBLACKLISTLOAD=
LOGTAGONLY=
LOGALLNEW=
RFC1918_STRICT=
MACLIST_TTL=
2005-07-09 07:55:29 +02:00
SAVE_IPSETS=
RESTOREFILE=
2005-07-26 01:08:09 +02:00
MAPOLDACTIONS=
2005-07-09 07:45:05 +02:00
2005-07-09 06:45:32 +02:00
RESTOREBASE=
TMP_DIR=
2005-07-09 07:45:05 +02:00
ALL_INTERFACES=
2005-07-09 07:55:29 +02:00
ROUTEMARK_INTERFACES=
2005-08-01 22:35:28 +02:00
IPSECMARK=256
2005-07-09 07:55:29 +02:00
PROVIDERS=
2005-07-26 01:08:09 +02:00
CRITICALHOSTS=
IPSECFILE=
2005-08-05 17:52:03 +02:00
EXCLUSION_SEQ=1
2003-01-07 00:01:23 +01:00
2005-08-23 22:41:18 +02:00
STOPPING=
HAVE_MUTEX=
ALIASES_TO_ADD=
2005-08-27 16:39:43 +02:00
SECTION=ESTABLISHED
2005-08-26 19:16:09 +02:00
SECTIONS=
2002-05-01 01:13:15 +02:00
2003-03-08 18:55:34 +01:00
FUNCTIONS=$SHARED_DIR/functions
if [ -f $FUNCTIONS ]; then
2005-07-09 06:45:32 +02:00
[ -n "$QUIET" ] || echo "Loading $FUNCTIONS..."
2003-03-08 18:55:34 +01:00
. $FUNCTIONS
2003-03-07 00:21:25 +01:00
else
2003-03-08 18:55:34 +01:00
startup_error "$FUNCTIONS does not exist!"
2003-03-07 00:21:25 +01:00
fi
2005-07-09 06:45:32 +02:00
TMP_DIR=$(mktempdir)
[ -n "$TMP_DIR" ] && chmod 700 $TMP_DIR || \
startup_error "Can't create a temporary directory"
trap "rm -rf $TMP_DIR; my_mutex_off; exit 2" 1 2 3 4 5 6 9
ensure_config_path
2003-03-08 19:01:32 +01:00
VERSION_FILE=$SHARED_DIR/version
2005-07-09 06:45:32 +02:00
[ -f $VERSION_FILE ] && version=$(cat $VERSION_FILE)
2003-03-08 19:01:32 +01:00
2003-03-08 18:55:34 +01:00
run_user_exit params
2003-03-07 00:21:25 +01:00
2005-07-09 06:45:32 +02:00
config=$(find_file shorewall.conf)
2003-02-23 15:10:37 +01:00
2003-01-07 00:01:23 +01:00
if [ -f $config ]; then
2005-07-09 06:45:32 +02:00
if [ -r $config ]; then
[ -n "$QUIET" ] || echo "Processing $config..."
. $config
else
2005-09-18 00:37:32 +02:00
startup_error "Cannot read $config (Hint: Are you root?)"
2005-07-09 06:45:32 +02:00
fi
2003-01-07 00:01:23 +01:00
else
2005-09-18 00:37:32 +02:00
startup_error "$config does not exist!"
2002-05-01 01:13:15 +02:00
fi
2003-07-22 16:25:36 +02:00
#
2005-07-09 06:45:32 +02:00
# Restore CONFIG_PATH if the shorewall.conf file cleared it
#
ensure_config_path
#
2003-07-22 16:25:36 +02:00
# Determine the capabilities of the installed iptables/netfilter
2005-08-02 18:46:30 +02:00
# We load the kernel modules here to accurately determine
2005-07-09 06:45:32 +02:00
# capabilities when module autoloading isn't enabled.
2003-07-22 16:25:36 +02:00
#
2005-07-09 06:45:32 +02:00
2005-09-28 22:28:01 +02:00
[ -n "${MODULE_SUFFIX:=o gz ko o.gz ko.gz}" ]
2005-07-09 06:45:32 +02:00
load_kernel_modules
2005-07-09 07:45:05 +02:00
if [ -z "$IPTABLES" ]; then
2005-07-27 22:30:16 +02:00
IPTABLES=$(mywhich iptables 2> /dev/null)
2005-07-09 07:45:05 +02:00
[ -z "$IPTABLES" ] && startup_error "Can't find iptables executable"
else
[ -e "$IPTABLES" ] || startup_error "\$IPTABLES=$IPTABLES does not exist or is not executable"
fi
2005-08-14 21:26:17 +02:00
PKTTYPE=$(added_param_value_no PKTTYPE $PKTTYPE)
2005-07-09 07:45:05 +02:00
2003-07-22 16:25:36 +02:00
determine_capabilities
2002-05-01 01:13:15 +02:00
2005-07-26 01:08:09 +02:00
[ -d /var/lib/shorewall ] || mkdir -p /var/lib/shorewall
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
ALLOWRELATED="$(added_param_value_yes ALLOWRELATED $ALLOWRELATED)"
2003-02-08 21:58:44 +01:00
[ -n "$ALLOWRELATED" ] || \
startup_error "ALLOWRELATED=No is not supported"
2005-07-09 06:45:32 +02:00
ADD_IP_ALIASES="$(added_param_value_yes ADD_IP_ALIASES $ADD_IP_ALIASES)"
TC_ENABLED="$(added_param_value_yes TC_ENABLED $TC_ENABLED)"
2002-05-01 01:13:15 +02:00
if [ -n "${LOGRATE}${LOGBURST}" ]; then
2003-08-22 17:27:08 +02:00
LOGLIMIT="--match limit"
[ -n "$LOGRATE" ] && LOGLIMIT="$LOGLIMIT --limit $LOGRATE"
[ -n "$LOGBURST" ] && LOGLIMIT="$LOGLIMIT --limit-burst $LOGBURST"
2002-05-01 01:13:15 +02:00
fi
if [ -n "$IP_FORWARDING" ]; then
case "$IP_FORWARDING" in
[Oo][Nn]|[Oo][Ff][Ff]|[Kk][Ee][Ee][Pp])
2002-07-06 00:24:40 +02:00
;;
*)
2002-05-01 01:13:15 +02:00
startup_error "Invalid value ($IP_FORWARDING) for IP_FORWARDING"
;;
esac
else
IP_FORWARDING=On
fi
2005-10-06 00:51:29 +02:00
[ -n "${BLACKLIST_DISPOSITION:=DROP}" ]
2005-08-02 18:46:30 +02:00
2005-07-09 07:45:05 +02:00
case "$CLAMPMSS" in
[0-9]*)
;;
*)
CLAMPMSS=$(added_param_value_no CLAMPMSS $CLAMPMSS)
;;
esac
2005-08-02 18:46:30 +02:00
2005-07-09 06:45:32 +02:00
ADD_SNAT_ALIASES=$(added_param_value_no ADD_SNAT_ALIASES $ADD_SNAT_ALIASES)
ROUTE_FILTER=$(added_param_value_no ROUTE_FILTER $ROUTE_FILTER)
2005-07-09 07:45:05 +02:00
LOG_MARTIANS=$(added_param_value_no LOG_MARTIANS $LOG_MARTIANS)
2005-07-09 06:45:32 +02:00
DETECT_DNAT_IPADDRS=$(added_param_value_no DETECT_DNAT_IPADDRS $DETECT_DNAT_IPADDRS)
FORWARDPING=$(added_param_value_no FORWARDPING $FORWARDPING)
2003-02-08 21:58:44 +01:00
[ -n "$FORWARDPING" ] && \
startup_error "FORWARDPING=Yes is no longer supported"
2003-06-12 01:57:35 +02:00
maclist_target=reject
2003-02-23 15:10:37 +01:00
2002-10-22 20:07:52 +02:00
if [ -n "$MACLIST_DISPOSITION" ] ; then
case $MACLIST_DISPOSITION in
REJECT)
;;
2005-07-18 00:08:15 +02:00
DROP)
maclist_target=DROP
;;
ACCEPT)
maclist_target=RETURN
2002-10-22 20:07:52 +02:00
;;
*)
startup_error "Invalid value ($MACLIST_DISPOSITION) for MACLIST_DISPOSITION"
;;
esac
else
2003-06-12 01:57:35 +02:00
MACLIST_DISPOSITION=REJECT
2002-10-22 20:07:52 +02:00
fi
2002-11-10 22:34:20 +01:00
if [ -n "$TCP_FLAGS_DISPOSITION" ] ; then
case $TCP_FLAGS_DISPOSITION in
REJECT|ACCEPT|DROP)
;;
*)
startup_error "Invalid value ($TCP_FLAGS_DISPOSITION) for TCP_FLAGS_DISPOSITION"
;;
esac
else
TCP_FLAGS_DISPOSITION=DROP
fi
2005-09-28 22:28:01 +02:00
[ -n "${RFC1918_LOG_LEVEL:=info}" ]
2005-07-09 06:45:32 +02:00
MARK_IN_FORWARD_CHAIN=$(added_param_value_no MARK_IN_FORWARD_CHAIN $MARK_IN_FORWARD_CHAIN)
2005-07-09 07:45:05 +02:00
[ -n "$MARK_IN_FORWARD_CHAIN" ] && MARKING_CHAIN=tcfor || MARKING_CHAIN=tcpre
2005-10-06 00:51:29 +02:00
CLEAR_TC=$(added_param_value_yes CLEAR_TC $CLEAR_TC)
2005-08-02 18:46:30 +02:00
2003-05-22 22:37:24 +02:00
if [ -n "$LOGFORMAT" ]; then
2005-07-09 06:45:32 +02:00
if [ -n "$(echo $LOGFORMAT | grep '%d')" ]; then
2003-05-27 19:49:13 +02:00
LOGRULENUMBERS=Yes
2005-07-09 06:45:32 +02:00
temp=$(printf "$LOGFORMAT" fooxx 1 barxx 2> /dev/null)
2003-05-28 21:20:23 +02:00
if [ $? -ne 0 ]; then
2003-05-27 19:49:13 +02:00
startup_error "Invalid LOGFORMAT string: \"$LOGFORMAT\""
fi
else
2005-07-09 06:45:32 +02:00
temp=$(printf "$LOGFORMAT" fooxx barxx 2> /dev/null)
2003-05-28 21:20:23 +02:00
if [ $? -ne 0 ]; then
2003-05-27 19:49:13 +02:00
startup_error "Invalid LOGFORMAT string: \"$LOGFORMAT\""
fi
2003-05-22 22:37:24 +02:00
fi
2003-05-28 21:20:23 +02:00
2005-07-09 07:45:05 +02:00
[ ${#temp} -le 29 ] || startup_error "LOGFORMAT string is longer than 29 characters: \"$LOGFORMAT\""
2003-05-22 22:37:24 +02:00
else
2003-05-27 19:42:12 +02:00
LOGFORMAT="Shorewall:%s:%s:"
2003-05-22 22:37:24 +02:00
fi
2005-07-09 06:45:32 +02:00
ADMINISABSENTMINDED=$(added_param_value_no ADMINISABSENTMINDED $ADMINISABSENTMINDED)
BLACKLISTNEWONLY=$(added_param_value_no BLACKLISTNEWONLY $BLACKLISTNEWONLY)
DISABLE_IPV6=$(added_param_value_no DISABLE_IPV6 $DISABLE_IPV6)
BRIDGING=$(added_param_value_no BRIDGING $BRIDGING)
DYNAMIC_ZONES=$(added_param_value_no DYNAMIC_ZONES $DYNAMIC_ZONES)
2005-07-09 07:45:05 +02:00
STARTUP_ENABLED=$(added_param_value_yes STARTUP_ENABLED $STARTUP_ENABLED)
RETAIN_ALIASES=$(added_param_value_no RETAIN_ALIASES $RETAIN_ALIASES)
DELAYBLACKLISTLOAD=$(added_param_value_no DELAYBLACKLISTLOAD $DELAYBLACKLISTLOAD)
LOGTAGONLY=$(added_param_value_no LOGTAGONLY $LOGTAGONLY)
RFC1918_STRICT=$(added_param_value_no RFC1918_STRICT $RFC1918_STRICT)
2005-07-26 01:08:09 +02:00
SAVE_IPSETS=$(added_param_value_no SAVE_IPSETS $SAVE_IPSETS)
2005-08-02 18:46:30 +02:00
MAPOLDACTIONS=$(added_param_value_yes MAPOLDACTIONS $MAPOLDACTIONS)
2005-08-11 21:53:07 +02:00
FASTACCEPT=$(added_param_value_no FASTACCEPT $FASTACCEPT)
2005-07-26 01:08:09 +02:00
case ${IPSECFILE:=ipsec} in
ipsec|zones)
;;
*)
startup_error "Invalid value ($IPSECFILE) for IPSECFILE option"
;;
esac
2005-10-06 22:01:51 +02:00
case ${MACLIST_TABLE:=filter} in
filter)
;;
mangle)
[ $MACLIST_DISPOSITION = reject ] && startup_error "MACLIST_DISPOSITION=REJECT is not allowed with MACLIST_TABLE=mangle"
;; *)
startup_error "Invalid value ($MACLIST_TABLE) for MACLIST_TABLE option"
;;
esac
2005-07-26 01:08:09 +02:00
[ "x${SHOREWALL_DIR}" = "x." ] && SHOREWALL_DIR="$PWD"
2003-01-07 00:01:23 +01:00
#
# Strip the files that we use often
#
strip_file interfaces
strip_file hosts
2003-06-27 23:02:52 +02:00
#
2003-07-01 22:29:01 +02:00
# Check out the user's shell
#
2005-09-28 22:28:01 +02:00
[ -n "${SHOREWALL_SHELL:=/bin/sh}" ]
2003-06-27 23:02:52 +02:00
2005-08-02 18:46:30 +02:00
temp=$(decodeaddr 192.168.1.1)
2005-07-09 06:45:32 +02:00
if [ $(encodeaddr $temp) != 192.168.1.1 ]; then
2003-07-01 22:29:01 +02:00
startup_error "Shell $SHOREWALL_SHELL is broken and may not be used with Shorewall"
fi
2005-07-09 06:45:32 +02:00
rm -f $TMP_DIR/physdev
2005-07-09 07:45:05 +02:00
rm -f $TMP_DIR/iprange
2002-05-01 01:13:15 +02:00
}
2002-10-23 18:48:40 +02:00
#
# Give Usage Information
#
2002-05-01 01:13:15 +02:00
usage() {
2005-07-29 20:32:50 +02:00
echo "Usage: $0 [debug] {start|stop|reset|restart|refresh|clear|{add|delete} <interface>[:hosts] zone}}"
2002-05-01 01:13:15 +02:00
exit 1
}
2002-10-23 18:48:40 +02:00
#
# E X E C U T I O N B E G I N S H E R E
#
2002-05-01 01:13:15 +02:00
#
# Start trace if first arg is "debug"
#
[ $# -gt 1 ] && [ "$1" = "debug" ] && { set -x ; shift ; }
nolock=
[ $# -gt 1 ] && [ "$1" = "nolock" ] && { nolock=Yes; shift ; }
2002-07-30 01:53:26 +02:00
trap "my_mutex_off; exit 2" 1 2 3 4 5 6 9
2005-07-09 06:45:32 +02:00
COMMAND="$1"
2002-05-01 01:13:15 +02:00
2005-07-09 06:45:32 +02:00
case "$COMMAND" in
2002-05-01 01:13:15 +02:00
stop)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-05-01 01:13:15 +02:00
do_initialize
my_mutex_on
2003-07-28 19:32:41 +02:00
#
# Don't want to do a 'stop' when startup is disabled
#
2005-08-02 18:46:30 +02:00
check_disabled_startup
2002-05-01 01:13:15 +02:00
echo -n "Stopping Shorewall..."
stop_firewall
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
echo "done."
my_mutex_off
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
start)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-05-01 01:13:15 +02:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if shorewall_is_started ; then
2002-05-01 01:13:15 +02:00
[ -n "$SUBSYSLOCK" ] && touch $SUBSYSLOCK
echo "Shorewall Already Started"
2002-09-29 23:28:44 +02:00
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
2002-05-01 01:13:15 +02:00
my_mutex_off
exit 0;
fi
define_firewall "Start" && [ -n "$SUBSYSLOCK" ] && touch $SUBSYSLOCK
2002-05-18 15:45:23 +02:00
my_mutex_off
2002-05-01 01:13:15 +02:00
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
restart)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-05-01 01:13:15 +02:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if shorewall_is_started; then
2002-05-01 01:13:15 +02:00
define_firewall "Restart"
else
echo "Shorewall Not Currently Running"
define_firewall "Start"
fi
[ $? -eq 0 ] && [ -n "$SUBSYSLOCK" ] && touch $SUBSYSLOCK
my_mutex_off
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
reset)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-10-30 16:56:46 +01:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if ! shorewall_is_started ; then
2002-10-30 16:56:46 +01:00
echo "Shorewall Not Started"
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
my_mutex_off
exit 2;
fi
2005-07-09 07:45:05 +02:00
$IPTABLES -Z
$IPTABLES -t nat -Z
$IPTABLES -t mangle -Z
2002-05-03 00:56:27 +02:00
report "Shorewall Counters Reset"
2005-07-26 01:08:09 +02:00
date > /var/lib/shorewall/restarted
2002-10-30 16:56:46 +01:00
my_mutex_off
2002-05-01 01:13:15 +02:00
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
refresh)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-05-01 01:13:15 +02:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if ! shorewall_is_started ; then
2002-05-01 01:13:15 +02:00
echo "Shorewall Not Started"
2002-09-29 23:28:44 +02:00
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
2002-05-01 01:13:15 +02:00
my_mutex_off
exit 2;
2002-07-06 00:24:40 +02:00
fi
2002-05-01 01:13:15 +02:00
refresh_firewall;
my_mutex_off
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
clear)
2002-10-01 22:54:42 +02:00
[ $# -ne 1 ] && usage
2002-05-01 01:13:15 +02:00
do_initialize
my_mutex_on
echo -n "Clearing Shorewall..."
clear_firewall
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
echo "done."
my_mutex_off
;;
2002-05-30 14:55:47 +02:00
2003-02-27 23:28:06 +01:00
check)
[ $# -ne 1 ] && usage
do_initialize
check_config
;;
2003-03-24 22:56:31 +01:00
2002-10-01 22:54:42 +02:00
add)
2005-07-09 07:45:05 +02:00
[ $# -lt 3 ] && usage
2002-10-01 22:54:42 +02:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if ! shorewall_is_started ; then
2002-10-01 22:54:42 +02:00
echo "Shorewall Not Started"
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
my_mutex_off
exit 2;
fi
2005-07-09 07:45:05 +02:00
shift
add_to_zone $@
2002-10-01 22:54:42 +02:00
my_mutex_off
;;
2002-11-03 16:42:23 +01:00
2002-10-01 22:54:42 +02:00
delete)
2005-07-09 07:45:05 +02:00
[ $# -lt 3 ] && usage
2002-10-01 22:54:42 +02:00
do_initialize
my_mutex_on
2005-08-01 22:35:28 +02:00
if ! shorewall_is_started ; then
2002-10-01 22:54:42 +02:00
echo "Shorewall Not Started"
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
my_mutex_off
exit 2;
fi
2005-07-09 07:45:05 +02:00
shift
delete_from_zone $@
2002-10-01 22:54:42 +02:00
my_mutex_off
;;
2002-11-03 16:42:23 +01:00
2003-07-05 19:55:43 +02:00
call)
#
# Undocumented way to call functions in /usr/share/shorewall/firewall directly
#
shift;
do_initialize
2003-07-05 21:52:34 +02:00
EMPTY=
2003-07-05 19:55:43 +02:00
$@
;;
2005-07-09 07:55:29 +02:00
2002-05-01 01:13:15 +02:00
*)
usage
;;
2002-05-30 14:55:47 +02:00
2002-05-01 01:13:15 +02:00
esac