mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-27 16:49:05 +01:00
473f7d7361
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@4445 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
1040 lines
23 KiB
Bash
Executable File
1040 lines
23 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# The Shoreline Firewall (Shorewall) Packet Filtering Firewall - V3.2
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
#
|
|
# (c) 1999,2000,2001,2002,2003,2004,2005,2006 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# 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#
|
|
#
|
|
# Complete documentation is available at http://shorewall.net
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of Version 2 of the GNU General Public License
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
#
|
|
# If an error occurs while starting or restarting the firewall, the
|
|
# firewall is automatically stopped.
|
|
#
|
|
# Commands are:
|
|
#
|
|
# shorewall start Starts the firewall
|
|
# shorewall restart Restarts the firewall
|
|
# shorewall stop Stops the firewall
|
|
# shorewall reset Resets iptables packet and
|
|
# byte counts
|
|
# shorewall clear Remove all Shorewall chains
|
|
# and rules/policies.
|
|
#
|
|
# Mutual exclusion -- These functions are jackets for the mutual exclusion
|
|
# routines in $FUNCTIONS. They invoke
|
|
# the corresponding function in that file if the user did
|
|
# not specify "nolock" on the runline.
|
|
#
|
|
my_mutex_on() {
|
|
[ -n "$NOLOCK" ] || { mutex_on; HAVE_MUTEX=Yes; }
|
|
}
|
|
|
|
my_mutex_off() {
|
|
[ -n "$HAVE_MUTEX" ] && { mutex_off; HAVE_MUTEX=; }
|
|
}
|
|
|
|
#
|
|
# Fatal error -- stops the firewall after issuing the error message
|
|
#
|
|
fatal_error() # $* = Error Message
|
|
{
|
|
echo " ERROR: $@" >&2
|
|
stop_firewall
|
|
exit 2
|
|
}
|
|
|
|
#
|
|
# Fatal error during startup -- generate an error message and abend without
|
|
# altering the state of the firewall
|
|
#
|
|
startup_error() # $* = Error Message
|
|
{
|
|
echo " ERROR: $@" >&2
|
|
my_mutex_off
|
|
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
|
|
[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE
|
|
kill $$
|
|
exit 2
|
|
}
|
|
|
|
#
|
|
# Send a message to STDOUT and the System Log
|
|
#
|
|
report () { # $* = message
|
|
progress_message3 "$@"
|
|
logger "$@"
|
|
}
|
|
|
|
#
|
|
# Run iptables and if an error occurs, stop the firewall and quit
|
|
#
|
|
run_iptables() {
|
|
if [ -z "$KLUDGEFREE" ]; then
|
|
#
|
|
# Purge the temporary files that we use to prevent duplicate '-m' specifications
|
|
#
|
|
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
|
|
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
|
|
fi
|
|
|
|
if ! $IPTABLES $@ ; then
|
|
if [ -z "$STOPPING" ]; then
|
|
error_message "ERROR: Command \"$IPTABLES $@\" Failed"
|
|
stop_firewall
|
|
exit 2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Version of 'run_iptables' that inserts white space after "!" in the arg list
|
|
#
|
|
run_iptables2() {
|
|
|
|
case "$@" in
|
|
*!*)
|
|
run_iptables $(fix_bang $@)
|
|
;;
|
|
*)
|
|
run_iptables $@
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
#
|
|
# Quietly run iptables
|
|
#
|
|
qt_iptables() {
|
|
if [ -z "$KLUDGEFREE" ]; then
|
|
#
|
|
# Purge the temporary files that we use to prevent duplicate '-m' specifications
|
|
#
|
|
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
|
|
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
|
|
fi
|
|
|
|
qt $IPTABLES $@
|
|
}
|
|
|
|
#
|
|
# Run ip and if an error occurs, stop the firewall and quit
|
|
#
|
|
run_ip() {
|
|
if ! ip $@ ; then
|
|
if [ -z "$STOPPING" ]; then
|
|
error_message "ERROR: Command \"ip $@\" Failed"
|
|
stop_firewall
|
|
exit 2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Run tc and if an error occurs, stop the firewall and quit
|
|
#
|
|
run_tc() {
|
|
if ! tc $@ ; then
|
|
if [ -z "$STOPPING" ]; then
|
|
error_message "ERROR: Command \"tc $@\" Failed"
|
|
stop_firewall
|
|
exit 2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Delete a chain if it exists
|
|
#
|
|
deletechain() # $1 = name of chain
|
|
{
|
|
qt $IPTABLES -L $1 -n && qt $IPTABLES -F $1 && qt $IPTABLES -X $1
|
|
}
|
|
|
|
#
|
|
# Find broadcast addresses -- if we are compiling a script and 'detect' is specified for an interface
|
|
# the function returns nothing for that interface
|
|
#
|
|
find_broadcasts() {
|
|
for interface in $ALL_INTERFACES; do
|
|
eval bcast=\$$(chain_base $interface)_broadcast
|
|
if [ "x$bcast" = "xdetect" ]; then
|
|
ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u
|
|
elif [ "x${bcast}" != "x-" ]; then
|
|
echo $(separate_list $bcast)
|
|
fi
|
|
done
|
|
}
|
|
|
|
#
|
|
# For each entry in the CRITICALHOSTS global list, add INPUT and OUTPUT rules to
|
|
# enable traffic to/from those hosts.
|
|
#
|
|
enable_critical_hosts()
|
|
{
|
|
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.
|
|
#
|
|
disable_critical_hosts()
|
|
{
|
|
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
|
|
}
|
|
|
|
#
|
|
# Stop the Firewall
|
|
#
|
|
stop_firewall() {
|
|
#
|
|
# Turn off trace unless we were tracing "stop" or "clear"
|
|
#
|
|
|
|
[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE
|
|
|
|
case $COMMAND in
|
|
stop|clear)
|
|
;;
|
|
*)
|
|
set +x
|
|
|
|
[ -n "${RESTOREFILE:=restore}" ]
|
|
|
|
RESTOREPATH=${VARDIR}/$RESTOREFILE
|
|
|
|
if [ -x $RESTOREPATH ]; then
|
|
|
|
if [ -x ${RESTOREPATH}-ipsets ]; then
|
|
progress_message2 Restoring Ipsets...
|
|
#
|
|
# We must purge iptables to be sure that there are no
|
|
# references to ipsets
|
|
#
|
|
for table in mangle nat filter; do
|
|
iptables -t $table -F
|
|
iptables -t $table -X
|
|
done
|
|
|
|
${RESTOREPATH}-ipsets
|
|
fi
|
|
|
|
echo Restoring Shorewall...
|
|
|
|
if $RESTOREPATH restore; then
|
|
echo "Shorewall restored from $RESTOREPATH"
|
|
set_state "Started"
|
|
else
|
|
set_state "Unknown"
|
|
fi
|
|
|
|
my_mutex_off
|
|
kill $$
|
|
exit 2
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
set_state "Stopping"
|
|
|
|
STOPPING="Yes"
|
|
|
|
TERMINATOR=
|
|
|
|
deletechain shorewall
|
|
|
|
run_user_exit stop
|
|
|
|
if [ -n "$MANGLE_ENABLED" ]; then
|
|
run_iptables -t mangle -F
|
|
run_iptables -t mangle -X
|
|
for chain in PREROUTING INPUT FORWARD POSTROUTING; do
|
|
qt $IPTABLES -t mangle -P $chain ACCEPT
|
|
done
|
|
fi
|
|
|
|
if [ -n "$RAW_TABLE" ]; then
|
|
run_iptables -t raw -F
|
|
run_iptables -t raw -X
|
|
for chain in PREROUTING OUTPUT; do
|
|
qt $IPTABLES -t raw -P $chain ACCEPT
|
|
done
|
|
fi
|
|
|
|
if [ -n "$NAT_ENABLED" ]; then
|
|
delete_nat
|
|
for chain in PREROUTING POSTROUTING OUTPUT; do
|
|
qt $IPTABLES -t nat -P $chain ACCEPT
|
|
done
|
|
fi
|
|
|
|
delete_proxy_arp
|
|
[ -n "$CLEAR_TC" ] && delete_tc1
|
|
|
|
[ -n "$DISABLE_IPV6" ] && disable_ipv6
|
|
|
|
process_criticalhosts
|
|
|
|
if [ -n "$CRITICALHOSTS" ]; then
|
|
if [ -z "$ADMINISABSENTMINDED" ]; then
|
|
for chain in INPUT OUTPUT; do
|
|
setpolicy $chain ACCEPT
|
|
done
|
|
|
|
setpolicy FORWARD DROP
|
|
|
|
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
|
|
|
|
deleteallchains
|
|
|
|
enable_critical_hosts
|
|
|
|
setpolicy INPUT DROP
|
|
|
|
for chain in INPUT FORWARD; do
|
|
setcontinue $chain
|
|
done
|
|
fi
|
|
elif [ -z "$ADMINISABSENTMINDED" ]; then
|
|
for chain in INPUT OUTPUT FORWARD; do
|
|
setpolicy $chain DROP
|
|
done
|
|
|
|
deleteallchains
|
|
else
|
|
for chain in INPUT FORWARD; do
|
|
setpolicy $chain DROP
|
|
done
|
|
|
|
setpolicy OUTPUT ACCEPT
|
|
|
|
deleteallchains
|
|
|
|
for chain in INPUT FORWARD; do
|
|
setcontinue $chain
|
|
done
|
|
fi
|
|
|
|
process_routestopped -A
|
|
|
|
$IPTABLES -A INPUT -i lo -j ACCEPT
|
|
[ -z "$ADMINISABSENTMINDED" ] && \
|
|
$IPTABLES -A OUTPUT -o lo -j ACCEPT
|
|
|
|
for interface in $(find_interfaces_by_option dhcp); do
|
|
$IPTABLES -A INPUT -p udp -i $interface --dport 67:68 -j ACCEPT
|
|
[ -z "$ADMINISABSENTMINDED" ] && \
|
|
$IPTABLES -A OUTPUT -p udp -o $interface --dport 67:68 -j ACCEPT
|
|
#
|
|
# This might be a bridge
|
|
#
|
|
$IPTABLES -A FORWARD -p udp -i $interface -o $interface --dport 67:68 -j ACCEPT
|
|
done
|
|
|
|
case "$IP_FORWARDING" in
|
|
[Oo][Nn])
|
|
echo 1 > /proc/sys/net/ipv4/ip_forward
|
|
progress_message2 "IP Forwarding Enabled"
|
|
;;
|
|
[Oo][Ff][Ff])
|
|
echo 0 > /proc/sys/net/ipv4/ip_forward
|
|
progress_message2 "IP Forwarding Disabled!"
|
|
;;
|
|
esac
|
|
|
|
run_user_exit stopped
|
|
|
|
set_state "Stopped"
|
|
|
|
logger "Shorewall Stopped"
|
|
|
|
rm -rf $TMP_DIR
|
|
|
|
case $COMMAND in
|
|
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
|
|
kill $$
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Remove all rules and remove all user-defined chains
|
|
#
|
|
clear_firewall() {
|
|
stop_firewall
|
|
|
|
setpolicy INPUT ACCEPT
|
|
setpolicy FORWARD ACCEPT
|
|
setpolicy OUTPUT ACCEPT
|
|
|
|
run_iptables -F
|
|
|
|
echo 1 > /proc/sys/net/ipv4/ip_forward
|
|
|
|
if [ -n "$DISABLE_IPV6" ] && qt mywhich ip6tables; then
|
|
ip6tables -P INPUT ACCEPT 2> /dev/null
|
|
ip6tables -P OUTPUT ACCEPT 2> /dev/null
|
|
ip6tables -P FORWARD ACCEPT 2> /dev/null
|
|
fi
|
|
|
|
run_user_exit clear
|
|
|
|
set_state "Cleared"
|
|
|
|
logger "Shorewall Cleared"
|
|
}
|
|
|
|
#
|
|
# Delete existing Proxy ARP
|
|
#
|
|
delete_proxy_arp() {
|
|
if [ -f ${VARDIR}/proxyarp ]; then
|
|
while read address interface external haveroute; do
|
|
case $COMMAND in
|
|
stop|clear)
|
|
qt arp -i $external -d $address pub
|
|
[ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface
|
|
;;
|
|
*)
|
|
if [ -n "$STOPPING" ]; then
|
|
qt arp -i $external -d $address pub
|
|
qt arp -i $external -d $address pub
|
|
[ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface
|
|
else
|
|
qt arp -i $external -d $address pub
|
|
if [ -z "$haveroute" ];then
|
|
[ -n "$NOROUTE" ] || qt ip route del $address dev $interface
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
done < ${VARDIR}/proxyarp
|
|
|
|
rm -f ${VARDIR}/proxyarp
|
|
fi
|
|
|
|
[ -d ${VARDIR} ] && touch ${VARDIR}/proxyarp
|
|
|
|
case $COMMAND in
|
|
stop|clear)
|
|
for f in /proc/sys/net/ipv4/conf/*; do
|
|
[ -f $f/proxy_arp ] && echo 0 > $f/proxy_arp
|
|
done
|
|
;;
|
|
*)
|
|
if [ -n "$STOPPING" ]; then
|
|
for f in /proc/sys/net/ipv4/conf/*; do
|
|
[ -f $f/proxy_arp ] && echo 0 > $f/proxy_arp
|
|
done
|
|
else
|
|
for f in /proc/sys/net/ipv4/conf/*; do
|
|
[ -f $f/proxy_arp ] && echo 0 > $f/proxy_arp
|
|
done
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Delete existing Static NAT
|
|
#
|
|
delete_nat() {
|
|
run_iptables -t nat -F
|
|
run_iptables -t nat -X
|
|
|
|
if [ -f ${VARDIR}/nat ]; then
|
|
while read external interface; do
|
|
qt ip addr del $external dev $interface
|
|
done < ${VARDIR}/nat
|
|
|
|
rm -f ${VARDIR}/nat
|
|
fi
|
|
|
|
[ -d ${VARDIR} ] && touch ${VARDIR}/nat
|
|
}
|
|
|
|
#
|
|
# Display elements of a list with leading white space
|
|
#
|
|
display_list() # $1 = List Title, rest of $* = list to display
|
|
{
|
|
[ $# -gt 1 ] && echo " $*"
|
|
}
|
|
|
|
#
|
|
# Verify that kernel has netfilter support
|
|
#
|
|
verify_os_version() {
|
|
|
|
osversion=$(uname -r)
|
|
|
|
case $osversion in
|
|
2.4.*|2.5.*|2.6.*)
|
|
;;
|
|
*)
|
|
startup_error "Shorewall version $VERSION does not work with kernel version $osversion"
|
|
;;
|
|
esac
|
|
|
|
[ $COMMAND = start -a -n "$(lsmod 2> /dev/null | grep '^ipchains')" ] && \
|
|
startup_error "Shorewall can't start with the ipchains kernel module loaded - see FAQ #8"
|
|
}
|
|
|
|
#
|
|
# Check for disabled startup
|
|
#
|
|
check_disabled_startup() {
|
|
if [ -z "$STARTUP_ENABLED" ]; then
|
|
echo " Shorewall Startup is disabled -- to enable startup"
|
|
echo " after you have completed Shorewall configuration,"
|
|
echo " change the setting of STARTUP_ENABLED to Yes in"
|
|
echo " ${CONFDIR}/shorewall.conf"
|
|
|
|
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
|
|
my_mutex_off
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Add a host or networks to a zone
|
|
#
|
|
add_to_zone() # $1...${n-1} = <interface>[:<hosts>] $n = zone
|
|
{
|
|
local interface host zone z h z1 z2 chain
|
|
local dhcp_interfaces blacklist_interfaces maclist_interfaces
|
|
local tcpflags_interfaces newhostlist=
|
|
local rulenum source_chain dest_hosts iface hosts hostlist=
|
|
|
|
nat_chain_exists() # $1 = chain name
|
|
{
|
|
qt $IPTABLES -t nat -L $1 -n
|
|
}
|
|
|
|
do_iptables() # $@ = command
|
|
{
|
|
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
|
|
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
|
|
|
|
if ! $IPTABLES $@ ; then
|
|
error_message "ERROR: Can't add $newhost to zone $zone"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Load $zones
|
|
#
|
|
determine_zones
|
|
#
|
|
# Validate Interfaces File
|
|
#
|
|
validate_interfaces_file
|
|
#
|
|
# Validate Hosts File
|
|
#
|
|
validate_hosts_file
|
|
#
|
|
# Validate IPSec File
|
|
#
|
|
f=$(find_file $IPSECFILE)
|
|
|
|
[ -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
|
|
#
|
|
# Validate Zone
|
|
#
|
|
zone=$1
|
|
|
|
validate_zone $zone || startup_error "Unknown zone: $zone"
|
|
|
|
[ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone"
|
|
|
|
#
|
|
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
|
#
|
|
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
|
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
|
#
|
|
# Check for duplicates and create a new zone state file
|
|
#
|
|
> ${VARDIR}/zones_$$
|
|
|
|
while read z type hosts; do
|
|
if [ "$z" = "$zone" ]; then
|
|
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
|
|
done
|
|
|
|
[ -z "$hosts" ] && hosts=$newhostlist || hosts="$hosts $newhostlist"
|
|
fi
|
|
|
|
eval ${z}_hosts=\"$hosts\"
|
|
|
|
echo "$z $type $hosts" >> ${VARDIR}/zones_$$
|
|
done < ${VARDIR}/zones
|
|
|
|
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
|
|
|
TERMINATOR=fatal_error
|
|
#
|
|
# Create a new Zone state file
|
|
#
|
|
for newhost in $newhostlist; do
|
|
#
|
|
# 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
|
|
|
|
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
|
|
[ "$z1" = "$z2" ] && op="-I" || op="-A"
|
|
if [ "$z1" = "$zone" ]; then
|
|
if [ "$z2" = "$FW" ]; then
|
|
do_iptables $op $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
|
|
else
|
|
source_chain=$(dynamic_fwd $interface)
|
|
if is_ipsec_host $z1 $newhost ; then
|
|
do_iptables $op $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
|
|
else
|
|
eval dest_hosts=\"\$${z2}_hosts\"
|
|
|
|
for h in $dest_hosts; do
|
|
iface=${h%%:*}
|
|
hosts=${h#*:}
|
|
|
|
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
|
do_iptables $op $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
elif [ "$z2" = "$zone" ]; then
|
|
if [ "$z1" = "$FW" ]; then
|
|
#
|
|
# Add a rule to the dynamic out chain for the interface
|
|
#
|
|
do_iptables $op $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
|
else
|
|
eval source_hosts=\"\$${z1}_hosts\"
|
|
|
|
for h in $source_hosts; do
|
|
iface=${h%%:*}
|
|
hosts=${h#*:}
|
|
|
|
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
|
if is_ipsec_host $z1 $h; then
|
|
do_iptables $op ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
|
else
|
|
do_iptables $op $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
done < ${VARDIR}/chains
|
|
|
|
progress_message "$newhost added to zone $zone"
|
|
|
|
done
|
|
|
|
rm -rf $TMP_DIR
|
|
}
|
|
|
|
#
|
|
# Delete a host or networks from a zone
|
|
#
|
|
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
|
|
{
|
|
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=
|
|
|
|
#
|
|
# Load $zones
|
|
#
|
|
determine_zones
|
|
#
|
|
# Validate Interfaces File
|
|
#
|
|
validate_interfaces_file
|
|
#
|
|
# 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
|
|
#
|
|
# Validate Zone
|
|
#
|
|
zone=$1
|
|
|
|
validate_zone $zone || startup_error "Unknown zone: $zone"
|
|
|
|
[ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
|
|
|
|
#
|
|
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
|
#
|
|
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
|
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
|
#
|
|
# Delete the passed hosts from the zone state file
|
|
#
|
|
> ${VARDIR}/zones_$$
|
|
|
|
while read z hosts; do
|
|
if [ "$z" = "$zone" ]; then
|
|
temp=$hosts
|
|
hosts=
|
|
|
|
for host in $hostlist; do
|
|
found=
|
|
for h in $temp; do
|
|
if [ "$h" = "$host" ]; then
|
|
found=Yes
|
|
break
|
|
fi
|
|
done
|
|
|
|
[ -n "$found" ] || error_message "WARNING: $host does not appear to be in zone $zone"
|
|
done
|
|
|
|
for h in $temp; do
|
|
found=
|
|
for host in $hostlist; do
|
|
if [ "$h" = "$host" ]; then
|
|
found=Yes
|
|
break
|
|
fi
|
|
done
|
|
|
|
[ -n "$found" ] || hosts="$hosts $h"
|
|
done
|
|
fi
|
|
|
|
eval ${z}_hosts=\"$hosts\"
|
|
|
|
echo "$z $hosts" >> ${VARDIR}/zones_$$
|
|
done < ${VARDIR}/zones
|
|
|
|
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
|
|
|
TERMINATOR=fatal_error
|
|
|
|
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\"
|
|
|
|
[ "$z2" = "$zone" ] && dest_hosts="$dest_hosts $hostlist"
|
|
|
|
for h in $dest_hosts; do
|
|
iface=${h%%:*}
|
|
hosts=${h#*:}
|
|
|
|
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
|
|
fi
|
|
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\"
|
|
|
|
for h in $source_hosts; do
|
|
iface=${h%%:*}
|
|
hosts=${h#*:}
|
|
|
|
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
|
|
fi
|
|
done < ${VARDIR}/chains
|
|
|
|
progress_message "$delhost removed from zone $zone"
|
|
|
|
done
|
|
|
|
rm -rf $TMP_DIR
|
|
}
|
|
|
|
#
|
|
# Give Usage Information
|
|
#
|
|
usage() {
|
|
echo "Usage: $0 [debug] {start|stop|reset|restart|clear}"
|
|
exit 1
|
|
}
|
|
|
|
#
|
|
# E X E C U T I O N B E G I N S H E R E
|
|
#
|
|
#
|
|
# Start trace if first arg is "debug"
|
|
#
|
|
[ $# -gt 1 ] && [ "$1" = "debug" ] && { set -x ; shift ; }
|
|
|
|
NOLOCK=
|
|
|
|
[ $# -gt 1 ] && [ "$1" = "nolock" ] && { NOLOCK=Yes; shift ; }
|
|
|
|
trap "my_mutex_off; exit 2" 1 2 3 4 5 6 9
|
|
|
|
SHAREDIR=/usr/share/shorewall
|
|
VARDIR=/var/lib/shorewall
|
|
CONFDIR=/etc/shorewall
|
|
|
|
FUNCTIONS=${SHAREDIR}/functions
|
|
|
|
if [ -f $FUNCTIONS ]; then
|
|
[ $VERBOSE -ge 2 ] && echo "Loading $FUNCTIONS..."
|
|
. $FUNCTIONS
|
|
else
|
|
startup_error "$FUNCTIONS does not exist!"
|
|
fi
|
|
|
|
PROGRAM=firewall
|
|
|
|
COMMAND="$1"
|
|
|
|
case "$COMMAND" in
|
|
stop)
|
|
[ $# -ne 1 ] && usage
|
|
do_initialize
|
|
my_mutex_on
|
|
#
|
|
# Don't want to do a 'stop' when startup is disabled
|
|
#
|
|
check_disabled_startup
|
|
progress_message3 "Stopping Shorewall..."
|
|
stop_firewall
|
|
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
progress_message3 "done."
|
|
my_mutex_off
|
|
;;
|
|
|
|
reset)
|
|
[ $# -ne 1 ] && usage
|
|
do_initialize
|
|
my_mutex_on
|
|
if ! shorewall_is_started ; then
|
|
echo "Shorewall Not Started"
|
|
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
|
|
my_mutex_off
|
|
exit 2;
|
|
fi
|
|
$IPTABLES -Z
|
|
$IPTABLES -t nat -Z
|
|
$IPTABLES -t mangle -Z
|
|
report "Shorewall Counters Reset"
|
|
date > ${VARDIR}/restarted
|
|
my_mutex_off
|
|
;;
|
|
|
|
clear)
|
|
[ $# -ne 1 ] && usage
|
|
do_initialize
|
|
my_mutex_on
|
|
progress_message3 "Clearing Shorewall..."
|
|
clear_firewall
|
|
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
progress_message3 "done."
|
|
my_mutex_off
|
|
;;
|
|
|
|
add)
|
|
[ $# -lt 3 ] && usage
|
|
do_initialize
|
|
my_mutex_on
|
|
if ! shorewall_is_started ; then
|
|
echo "Shorewall Not Started"
|
|
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
|
|
my_mutex_off
|
|
exit 2;
|
|
fi
|
|
shift
|
|
add_to_zone $@
|
|
my_mutex_off
|
|
;;
|
|
|
|
delete)
|
|
[ $# -lt 3 ] && usage
|
|
do_initialize
|
|
my_mutex_on
|
|
if ! shorewall_is_started ; then
|
|
echo "Shorewall Not Started"
|
|
[ -n "$TMP_DIR" ] && rm -rf $TMP_DIR
|
|
my_mutex_off
|
|
exit 2;
|
|
fi
|
|
shift
|
|
delete_from_zone $@
|
|
my_mutex_off
|
|
;;
|
|
|
|
call)
|
|
#
|
|
# Undocumented way to call functions in ${SHAREDIR}/firewall directly
|
|
#
|
|
shift
|
|
do_initialize
|
|
EMPTY=
|
|
$@
|
|
;;
|
|
|
|
*)
|
|
usage
|
|
;;
|
|
|
|
esac
|