#!/bin/sh

###############################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
###############################################################################

# Default script to execute
APP_LUA="/usr/clearos/apps/firewall/deploy/firewall.lua"

# Multipath synchronization flag
if [ "$1" == "--multipath-sync" ]; then
    shift 1
    MULTIPATH_SYNC="true"
    APP_LUA="/usr/clearos/apps/firewall/deploy/multipath-sync.lua"
fi

# ACCEPT and DROP default chain names
export FW_DROP="DROP"
export FW_ACCEPT="ACCEPT"

# Log all dropped packets?
export FW_LOG_DROPS="no"

# Configuration
export FW_ADHOC=${FW_ADHOC:-"/etc/clearos/firewall.d/local"}
export FW_CONF=${FW_CONF:-"/etc/clearos/firewall.conf"}
export FW_CUSTOM=${FW_CUSTOM:-"/etc/clearos/firewall.d/custom"}
export FW_TYPES="/etc/clearos/firewall.d/types"
export FW_APP_RULES="$(find /etc/clearos/firewall.d -maxdepth 1 | egrep '/[0-9]+-*' | sort -t - -n)"
export BANDWIDTH_CONF="/etc/clearos/bandwidth.conf"
export QOS_CONF="/etc/clearos/qos.conf"
export MULTIWAN_CONF="/etc/clearos/multiwan.conf"
export NETWORK_CONF="/etc/clearos/network.conf"
export PROTOCOL_CONF="/etc/clearos/protocol_filter.conf"

# Default mode
export FW_DEFAULT_MODE="trustedstandalone"

# Binaries
export APP_FW="/sbin/app-firewall"
export IPBIN="/sbin/ip"
export IPTABLES="/sbin/iptables"
export MODPROBE="/sbin/modprobe"
export RMMOD="/sbin/rmmod"
export SYSCTL="/sbin/sysctl"
export SYSWATCH_STATE="/var/lib/syswatch/state"
export TCBIN="/sbin/tc"

# Logging
export FW_FACILITY=${FW_FACILITY:-"local6"}

# Lockfile location
FW_LOCKFILE="/var/run/firewall.pid"

# Pretend mode?
PRETEND=0
for (( i=0; i<$#; i++)); do
    if [ ${BASH_ARGV[$i]} == "-p" ]; then
        PRETEND=1
        break
    fi
done

# TODO: detect installer environment properly
# Bail if we are in installer environment
CHECK=`/sbin/pidof loader`
[ -n "$CHECK" ] && exit 0

# Pull in firewall types
source $FW_TYPES || exit 1

# Pull in bandwidth configuration
[ -e "$BANDWIDTH_CONF" ] && source $BANDWIDTH_CONF

# Pull in QoS configuration
[ -e "$QOS_CONF" ] && source $QOS_CONF

# Pull in network configuration
[ -e "$NETWORK_CONF" ] && source $NETWORK_CONF

# Pull in multiwan configuration
[ -e "$MULTIWAN_CONF" ] && source $MULTIWAN_CONF

# Pull in protocol filter configuration
[ -e "$PROTOCOL_CONF" ] && source $PROTOCOL_CONF

# Pull in network configuration, export gateway device
source /etc/sysconfig/network
export GATEWAYDEV

# Pull in syswatch interface list
source $FW_CONF
if [ -f "$SYSWATCH_STATE" ]; then
    source $SYSWATCH_STATE
else
    SYSWATCH_WANIF="$EXTIF"
fi

# TODO: A quick hack to determine proxy user authentication mode
USERAUTH=`grep "http_access.*webconfig_lan.*password" /etc/squid/squid.conf 2>/dev/null`
if [ -n "$USERAUTH" ]; then
    SQUID_USER_AUTHENTICATION="on"
else
    SQUID_USER_AUTHENTICATION="off"
fi

# Export firewall configuration
export MODE EXTIF LANIF HOTIF DMZIF WIFIF BANDWIDTH_QOS BANDWIDTH_UPSTREAM \
    BANDWIDTH_UPSTREAM_BURST BANDWIDTH_UPSTREAM_CBURST BANDWIDTH_DOWNSTREAM \
    BANDWIDTH_DOWNSTREAM_BURST BANDWIDTH_DOWNSTREAM_CBURST \
    QOS_ENABLE QOS_ENGINE QOS_UPSTREAM QOS_DOWNSTREAM \
    QOS_UPSTREAM_BWRES QOS_DOWNSTREAM_BWRES QOS_UPSTREAM_BWLIMIT QOS_DOWNSTREAM_BWLIMIT \
    QOS_PRIOMARK4 QOS_PRIOMARK6 QOS_PRIOMARK4_CUSTOM QOS_PRIOMARK6_CUSTOM \
    SQUID_TRANSPARENT SQUID_USER_AUTHENTICATION IPSEC_SERVER PPTP_SERVER \
    PPTP_PASSTHROUGH_FORCE ONE_TO_ONE_NAT_MODE LANNET MULTIPATH \
    MULTIPATH_WEIGHTS RULES MULTIPATH_SKIP_DOWN_WANIF FW_LOG_DROPS \
    SYSWATCH_WANIF EGRESS_FILTERING PROTOCOL_FILTERING

# Panic stamp file path
FW_PANIC_STAMP="/var/state/firewall/panic-stamp"

# Panic mode rules.  If the firewall fails, then we run these rules to ensure
# we have something sane configured.
RunPanicRules() {
    if [ $PRETEND -eq 1 ]; then return; fi

    echo "Running firewall panic mode..."
    /usr/bin/logger -p $FW_FACILITY.error -t firewall "Running firewall panic mode..."

    # Touch panic file.  Signals applications that there is something wrong.
    touch "$FW_PANIC_STAMP"

    for TABLE in filter nat mangle; do
        $IPTABLES -t $TABLE -F  # Flush all previous rules.
        $IPTABLES -t $TABLE -X  # Delete user-defined chains.
    done

    $IPTABLES -P INPUT DROP
    $IPTABLES -P OUTPUT DROP
    $IPTABLES -P FORWARD DROP

    # Allow ping for diagnostics
    $IPTABLES -A INPUT -p icmp -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -p icmp -j $FW_ACCEPT

    # Open 81 and 22
    $IPTABLES -I INPUT -p tcp --dport 81 -j $FW_ACCEPT
    $IPTABLES -I OUTPUT -p tcp --sport 81 -j $FW_ACCEPT
    $IPTABLES -I INPUT -p tcp --dport 22 -j $FW_ACCEPT
    $IPTABLES -I OUTPUT -p tcp --sport 22 -j $FW_ACCEPT

    # Allow DNS requests
    $IPTABLES -A INPUT -p udp --sport domain -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -p udp --dport domain -j $FW_ACCEPT
    $IPTABLES -A INPUT -p tcp --sport domain -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -p tcp --dport domain -j $FW_ACCEPT

    # Allow DHCP to startup
    $IPTABLES -A INPUT -p udp --dport bootpc --sport bootps -j $FW_ACCEPT
    $IPTABLES -A INPUT -p tcp --dport bootpc --sport bootps -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -p tcp --sport bootpc --dport bootps -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -p udp --sport bootpc --dport bootps -j $FW_ACCEPT

    # Allow high ports
    $IPTABLES -A OUTPUT -p tcp --sport 1024:65535 -j $FW_ACCEPT
    $IPTABLES -A INPUT -p tcp --dport 1024:65535 \
        -m state --state ESTABLISHED,RELATED -j $FW_ACCEPT

    # Allow everything on the loopback
    $IPTABLES -A INPUT -i lo -j $FW_ACCEPT
    $IPTABLES -A OUTPUT -o lo -j $FW_ACCEPT
}

# lua barfs if this is not loaded
modprobe ip_tables

# Run Lua application
RC=0
if (set -o noclobber; echo "$$" > "$FW_LOCKFILE") 2> /dev/null; then
    trap 'rm -f "$FW_LOCKFILE"; exit $RC' INT TERM EXIT

    if [ x$MULTIPATH_SYNC != "xtrue" ]; then
        # Remove panic stamp file
        rm -f "$FW_PANIC_STAMP"
    fi

    if ($APP_FW -s $@ $APP_LUA); then

        # Exit here if we were invoked only to sync multipath routing
        if [ x$MULTIPATH_SYNC == "xtrue" ]; then
            rm -f "$FW_LOCKFILE"
            exit $RC
        fi

        ID=`grep ^software_id /etc/product | awk '{ print $3 }'`
        /usr/bin/logger -p local6.notice -t firewall "Running post-firewall $ID"

        # Run Custom/ad-hoc rules
        # XXX: This used to be run before anything else, but because we are now
        # queueing rules until iptc_commit(), it makes no sense to run an
        # external script because whatever it does will be cleared by
        # iptc_commit().  Using the Advanced firewall rule creator in webconfig
        # will allow custom rules to be run before others.  Ad-hoc rules should
        # use -I to insert rules ahead of others if need be.
        if [ -e $FW_CUSTOM ]; then
            source $FW_CUSTOM || RC=1
            /usr/bin/logger -p local6.notice -t firewall "Running $FW_CUSTOM"
            /usr/bin/logger -p local6.notice -t firewall -f $FW_CUSTOM
        fi

        if [ -e $FW_ADHOC ]; then
            source $FW_ADHOC || RC=1
            /usr/bin/logger -p local6.notice -t firewall "Running $FW_ADHOC"
            /usr/bin/logger -p local6.notice -t firewall -f $FW_ADHOC
        fi

        for FW_APP in $FW_APP_RULES; do
            source $FW_APP || RC=1
            /usr/bin/logger -p local6.notice -t firewall "Running $FW_APP"
        done
    else
        RC=1
        if [ x$MULTIPATH_SYNC != "xtrue" ]; then
            RunPanicRules
        fi
    fi

    rm -f "$FW_LOCKFILE"
else
    echo "Failed to acquire lock: $FW_LOCKFILE (held by $(cat $FW_LOCKFILE))"
    exit 1
fi 

exit $RC

# vi: syntax=sh expandtab shiftwidth=4 softtabstop=4 tabstop=4
