From 2d5d02662a4be723100e1dc33cfcf92b1aa4a42c Mon Sep 17 00:00:00 2001 From: teastep Date: Sun, 22 Jan 2006 23:41:56 +0000 Subject: [PATCH] Complete spit of firewall and compiler git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@3350 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall/compiler | 9060 +++++++++++++++++++++++++++++++++++++++++++ Shorewall/firewall | 2519 +++--------- Shorewall/shorewall | 2 +- 3 files changed, 9582 insertions(+), 1999 deletions(-) create mode 100755 Shorewall/compiler diff --git a/Shorewall/compiler b/Shorewall/compiler new file mode 100755 index 000000000..7d8071662 --- /dev/null +++ b/Shorewall/compiler @@ -0,0 +1,9060 @@ +#!/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 +# 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 check Verify the configuration files. +# +# 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. +# + +# +# Fatal error -- stops the firewall after issuing the error message +# +fatal_error() # $* = Error Message +{ + echo " ERROR: $@" >&2 + [ -n "$TMP_DIR" ] && rm -rf $TMP_DIR + [ -n "$TMP_DIR1" ] && rm -rf $TMP_DIR1 + [ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE + 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 + [ -n "$TMP_DIR" ] && rm -rf $TMP_DIR + [ -n "$TMP_DIR1" ] && rm -rf $TMP_DIR1 + [ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE + kill $$ + exit 2 +} + +# +# Write the passed args to $RESTOREBASE +# +save_command() +{ + echo "${INDENT}${@}" >> $RESTOREBASE +} + +run_and_save_command() +{ + echo "${INDENT}${@}" >> $RESTOREBASE +} + +ensure_and_save_command() +{ + echo "${INDENT}${@}" >> $RESTOREBASE +} + +save_command_unindented() +{ + echo "${@}" >> $RESTOREBASE +} + +# +# Write a progress_message command to $RESTOREBASE +# +save_progress_message() +{ + echo >> $RESTOREBASE + echo "${INDENT}progress_message \"$@\"" >> $RESTOREBASE + echo >> $RESTOREBASE +} + +save_progress_message_short() +{ + echo "${INDENT}progress_message \"$@\"" >> $RESTOREBASE +} + +# +# Append a file in /var/lib/shorewall to $RESTOREBASE +# +append_file() # $1 = File Name +{ + save_command "cat > /var/lib/shorewall/$1 << __EOF__" + cat $STATEDIR/$1 >> $RESTOREBASE + save_command_unindented __EOF__ +} + +# +# Generate a command to run iptables +# +do_iptables() { + save_command \$IPTABLES $@ +} + +# +# Generate an IPTABLES command. Include hacks to work around iptables limitations +# +run_iptables() { + # + # 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 + + save_command "$IPTABLES_COMMAND $@" + +} + +# +# Version of 'run_iptables' that inserts white space after "!" in the arg list +# +run_iptables2() { + save_command run_iptables $(fix_bang $@) +} + +# +# Generate command to quietly run iptables +# +qt_iptables() { + # + # 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 + + save_command qt \$IPTABLES $@ +} + +# +# Run ip and if an error occurs, issue a message and quit +# +run_ip() { + if ! ip $@ ; then + error_message "ERROR: Command \"ip $@\" Failed" + rm -rf $TMP_DIR + exit 2 + fi +} + +# +# Generate a command to run tc +# +run_tc() { + save_command run_tc $@ +} + +# +# Add the implicit ACCEPT rules at the end of a rules file section +# +finish_chain_section() # $1 = canonical chain $2 = state list +{ + local policy policychain + + [ -n "$FASTACCEPT" ] || run_iptables -A $1 -m state --state $2 -j ACCEPT + + if list_search RELATED $(separate_list $2) ; then + 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 + ;; + esac + else + run_iptables -A $1 -p tcp --syn -j @$1 + fi + fi + else + eval policychain=\$${1}_policychain + + if eval test -n \"\$${policychain}_synparams\" ; then + run_iptables -A $1 -p tcp --syn -j @$policychain + fi + fi + fi +} + +finish_section() # $1 = Section(s) +{ + local zone zone1 chain + + 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 +} + +# +# 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 +# variable exists_${1} and set its value to Yes to indicate that the chain now +# exists. +# +createchain() # $1 = chain name, $2 = If "yes", do section-end processing +{ + local c=$(chain_base $1) + + run_iptables -N $1 + + if [ $2 = yes ]; then + case $SECTION in + NEW|DONE) + finish_chain_section $1 ESTABLISHED,RELATED + ;; + RELATED) + finish_chain_section $1 ESTABLISHED + ;; + esac + fi + + eval exists_${c}=Yes +} + +createchain2() # $1 = chain name, $2 = If "yes", create default rules +{ + local c=$(chain_base $1) + + ensurechain $1 + + if [ $2 = yes ]; then + case $SECTION in + NEW|DONE) + finish_chain_section $1 ESTABLISHED,RELATED + ;; + RELATED) + finish_chain_section $1 ESTABLISHED + ;; + esac + + fi + + eval exists_${c}=Yes +} + +# +# Determine if a chain exists +# +# When we create a chain "x", we create a variable named exists_x and +# set its value to Yes. This function tests for the "exists_" variable +# corresponding to the passed chain having the value of "Yes". +# +havechain() # $1 = name of chain +{ + local c=$(chain_base $1) + + eval test \"\$exists_${c}\" = Yes +} + +# +# Ensure that a chain exists (create it if it doesn't) +# +ensurechain() # $1 = chain name +{ + havechain $1 || createchain $1 yes +} + +ensurechain1() # $1 = chain name +{ + havechain $1 || createchain $1 no +} + +# +# Add a rule to a chain creating the chain if necessary +# +addrule() # $1 = chain name, remainder of arguments specify the rule +{ + ensurechain $1 + run_iptables -A $@ +} + +addrule2() # $1 = chain name, remainder of arguments specify the rule +{ + ensurechain $1 + run_iptables2 -A $@ +} + +# +# Query NetFilter about the existence of a filter chain +# +chain_exists() # $1 = chain name +{ + qt $IPTABLES -L $1 -n +} + +# +# Create a mangle chain +# +# Create a variable exists_mangle_${1} and set its value to Yes to indicate that +# the chain now exists. +# +createmanglechain() # $1 = chain name +{ + run_iptables -t mangle -N $1 + + eval exists_mangle_${1}=Yes +} + +# +# Determine if a mangle chain exists +# +# 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 +# corresponding to the passed chain having the value of "Yes". +# +havemanglechain() # $1 = name of chain +{ + eval test \"\$exists_mangle_${1}\" = Yes +} + +# +# Ensure that a mangle chain exists (create it if it doesn't) +# +ensuremanglechain() # $1 = chain name +{ + havemanglechain $1 || createmanglechain $1 +} + +# +# Create a nat chain +# +# Create a variable exists_nat_${1} and set its value to Yes to indicate that +# the chain now exists. +# +createnatchain() # $1 = chain name +{ + run_iptables -t nat -N $1 + + eval exists_nat_${1}=Yes +} + +# +# Determine if a nat chain exists +# +# 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 +# corresponding to the passed chain having the value of "Yes". +# +havenatchain() # $1 = name of chain +{ + eval test \"\$exists_nat_${1}\" = Yes +} + +# +# Ensure that a nat chain exists (create it if it doesn't) +# +ensurenatchain() # $1 = chain name +{ + havenatchain $1 || createnatchain $1 +} + +# +# Add a rule to a nat chain creating the chain if necessary +# +addnatrule() # $1 = chain name, remainder of arguments specify the rule +{ + ensurenatchain $1 + run_iptables2 -t nat -A $@ +} + +# +# Determine if a chain is a policy chain +# +is_policy_chain() # $1 = name of chain +{ + eval test \"\$${1}_is_policy\" = Yes +} + +# +# Set a standard chain's policy +# +setpolicy() # $1 = name of chain, $2 = policy +{ + run_iptables -P $1 $2 +} + +# +# Set a standard chain to enable established and related connections +# +setcontinue() # $1 = name of chain +{ + run_iptables -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT +} + +# +# Flush one of the NAT table chains +# +flushnat() # $1 = name of chain +{ + run_iptables -t nat -F $1 +} + +# +# Flush one of the Mangle table chains +# +flushmangle() # $1 = name of chain +{ + run_iptables -t mangle -F $1 +} + +# +# This function assumes that the TMP_DIR variable is set and that +# its value named an existing directory. +# +determine_zones() +{ + local zone parent parents rest new_zone_file= r + + merge_zone() + { + local z zones="$ZONES" merged= + + 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 + } + + strip_file zones + + ZONES= + IPV4_ZONES= + IPSEC_ZONES= + + [ "$IPSECFILE" = zones ] && new_zone_file=Yes || test -n "${FW:=fw}" + + 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 + [ "$parent" = "$FW" ] && startup_error "Sub-zones of the firewall zone are not allowed" + list_search $parent $ZONES || startup_error "Parent zone not defined: $parent" + done + + [ ${#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" + ;; + all|none) + startup_error "Reserved zone name \"$zone\" in zones file" + ;; + esac + + if [ -n "$new_zone_file" ]; then + case ${type:=ipv4} in + ipv4|IPv4|IPV4|plain|-) + list_search $zone $ZONES $FW && startup_error "Zone $zone is defined more than once" + merge_zone + IPV4_ZONES="$IPV4_ZONES $zone" + ;; + ipsec|IPSEC|ipsec4|IPSEC4) + 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 + IPSEC_ZONES="$IPSEC_ZONES $zone" + ;; + firewall) + [ -n "$FW" ] && startup_error "Only one firewall zone may be defined" + list_search $zone $ZONES && startup_error "Zone $zone is defined more than once" + [ -n "$parents" ] && startup_error "The firewall zone may not be nested" + for r in $rest; do + [ "x$r" = x- ] || startup_error "OPTIONS not allowed on the firewall zone" + done + FW=$zone + ;; + *) + startup_error "Invalid Zone Type: $type" + ;; + esac + + eval ${zone}_type=$type + else + list_search $zone $ZONES $FW && startup_error "Zone $zone is defined more than once" + ZONES="$ZONES $zone" + IPV4_ZONES="$IPV4_ZONES $zone" + eval ${zone}_type=ipv4 + fi + done < $TMP_DIR/zones + + [ -z "$ZONES" ] && startup_error "No ipv4 or ipsec Zones Defined" + + [ -z "$FW" ] && startup_error "No Firewall Zone Defined" +} + +# +# Find interfaces to a given zone +# +# Search the variables representing the contents of the interfaces file and +# for each record matching the passed ZONE, echo the expanded contents of +# the "INTERFACE" column +# +find_interfaces() # $1 = interface zone +{ + local zne=$1 + local z + local interface + + for interface in $ALL_INTERFACES; do + eval z=\$$(chain_base $interface)_zone + [ "x${z}" = x${zne} ] && echo $interface + done +} + +# +# Forward Chain for an interface +# +forward_chain() # $1 = interface +{ + echo $(chain_base $1)_fwd +} + +# +# Input Chain for an interface +# +input_chain() # $1 = interface +{ + echo $(chain_base $1)_in +} + +# +# Output Chain for an interface +# +output_chain() # $1 = interface +{ + echo $(chain_base $1)_out +} + +# +# Masquerade Chain for an interface +# +masq_chain() # $1 = interface +{ + echo $(chain_base $1)_masq +} + +# +# MAC Verification Chain for an interface +# +mac_chain() # $1 = interface +{ + echo $(chain_base $1)_mac +} + +macrecent_target() # $1 - interface +{ + [ -n "$MACLIST_TTL" ] && echo $(chain_base $1)_rec || echo RETURN +} + +# +# 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 +} + +# +# DNAT Chain from a zone +# +dnat_chain() # $1 = zone +{ + echo ${1}_dnat +} + +# +# SNAT Chain to an interface +# +snat_chain() # $1 = interface +{ + echo $(chain_base $1)_snat +} + +# +# ECN Chain to an interface +# +ecn_chain() # $1 = interface +{ + echo $(chain_base $1)_ecn +} + +# +# First chains for an interface +# +first_chains() #$1 = interface +{ + local c=$(chain_base $1) + + echo ${c}_fwd ${c}_in +} + +# +# Horrible hack to work around an iptables limitation +# +iprange_echo() +{ + if [ -f $TMP_DIR/iprange ]; then + echo $@ + else + echo "-m iprange $@" + > $TMP_DIR/iprange + fi +} + +# +# 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)) + done + ;; + *\[*\]) + options=${1#*\[} + options=${options%\]} + setname=${1%\[*} + ;; + *) + ;; + esac + + echo "--set ${setname#+} $options" +} + +# +# Horrible hack to work around an iptables limitation +# +physdev_echo() +{ + if [ -f $TMP_DIR/physdev ]; then + echo $@ + else + echo -m physdev $@ + > $TMP_DIR/physdev + fi +} + +# +# 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. +# +match_source_hosts() +{ + if [ -n "$BRIDGING" ]; then + case $1 in + *:*) + physdev_echo "--physdev-in ${1%:*} $(source_ip_range ${1#*:})" + ;; + *.*.*.*|+*|!+*) + echo $(source_ip_range $1) + ;; + *) + physdev_echo "--physdev-in $1" + ;; + esac + else + echo $(source_ip_range $1) + fi +} + +match_dest_hosts() +{ + if [ -n "$BRIDGING" ]; then + case $1 in + *:*) + physdev_echo "--physdev-out ${1%:*} $(dest_ip_range ${1#*:})" + ;; + *.*.*.*|+*|!+*) + echo $(dest_ip_range $1) + ;; + *) + physdev_echo "--physdev-out $1" + ;; + esac + else + echo $(dest_ip_range $1) + fi +} + +# +# Similarly, the source or destination in a rule can be qualified by a device name. If +# the device is defined in /etc/shorewall/interfaces then a normal interface match is +# generated (-i or -o); otherwise, a physdev match is generated. +#------------------------------------------------------------------------------------- +# +# loosely match the passed interface with those in /etc/shorewall/interfaces. +# +known_interface() # $1 = interface name +{ + local iface + + for iface in $ALL_INTERFACES ; do + if if_match $iface $1 ; then + return 0 + fi + done + + return 1 +} + +known_port() # $1 = port name +{ + local port + + for port in $ALL_PORTS ; do + if if_match $port $1 ; then + return 0 + fi + done + + return 1 +} + +match_source_dev() +{ + if [ -n "$BRIDGING" ]; then + known_port $1 && physdev_echo "--physdev-in $1" || echo -i $1 + else + echo -i $1 + fi +} + +match_dest_dev() +{ + if [ -n "$BRIDGING" ]; then + known_port $1 && physdev_echo "--physdev-out $1" || echo -o $1 + else + echo -o $1 + fi +} + +verify_interface() +{ + known_interface $1 || { [ -n "$BRIDGING" ] && known_port $1 ; } +} + +# +# 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 +} + +# +# +# 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 +# +find_hosts() # $1 = host zone +{ + local hosts interface address addresses + + while read z hosts options; do + if [ "x$(expand $z)" = "x$1" ]; then + expandv hosts + interface=${hosts%%:*} + addresses=${hosts#*:} + for address in $(separate_list $addresses); do + echo $interface:$address + done + fi + done < $TMP_DIR/hosts +} + +# +# 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 +# +determine_interfaces() { + for zone in $ZONES; do + interfaces=$(find_interfaces $zone) + interfaces=$(echo $interfaces) # Remove extra trash + eval ${zone}_interfaces=\"\$interfaces\" + done +} + +# +# 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 +} + +# +# Determine the defined hosts in each zone and generate report +# +determine_hosts() { + for zone in $ZONES; do + hosts=$(find_hosts $zone) + hosts=$(echo $hosts) # Remove extra trash + + eval interfaces=\$${zone}_interfaces + + for interface in $interfaces; do + if interface_has_option $interface detectnets; then + networks=$(get_routed_networks $interface) + else + networks=0.0.0.0/0 + fi + + for network in $networks; do + if [ -z "$hosts" ]; then + hosts=$interface:$network + else + hosts="$hosts $interface:$network" + fi + + if interface_has_option $interface routeback; then + eval ${zone}_routeback=\"$interface:$network \$${zone}_routeback\" + fi + done + done + + interfaces= + + for host in $hosts; do + interface=${host%:*} + 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 + if [ -z "$interfaces" ]; then + interfaces=$interface + else + interfaces="$interfaces $interface" + fi + fi + done + + eval ${zone}_interfaces="\$interfaces" + eval ${zone}_hosts="\$hosts" + + if [ -n "$hosts" ]; then + [ $QUIET -lt 2 ] && display_list "$zone Zone:" $hosts + else + error_message "WARNING: Zone $zone is empty" + fi + done +} + +# +# Ensure that the passed zone is defined in the zones file or is the firewall +# +validate_zone() # $1 = zone +{ + list_search $1 $ZONES $FW +} +# +# Ensure that the passed zone is defined in the zones file. +# +validate_zone1() # $1 = zone +{ + list_search $1 $ZONES +} + +# +# Validate the zone names and options in the interfaces file +# +validate_interfaces_file() { + local wildcard + local found_obsolete_option= + local z interface networks options r iface option + + while read z interface networks options; do + expandv z interface networks options + r="$z $interface $networks $options" + + [ "x$z" = "x-" ] && z= + + if [ -n "$z" ]; then + validate_zone $z || startup_error "Invalid zone ($z) in record \"$r\"" + fi + + list_search $interface $ALL_INTERFACES && \ + startup_error "Duplicate Interface $interface" + + wildcard= + + case $interface in + *:*|+) + startup_error "Invalid Interface Name: $interface" + ;; + *+) + wildcard=Yes + ;; + esac + + ALL_INTERFACES="$ALL_INTERFACES $interface" + options=$(separate_list $options) + iface=$(chain_base $interface) + + eval ${iface}_broadcast="$networks" + eval ${iface}_zone="$z" + eval ${iface}_options=\"$options\" + + for option in $options; do + case $option in + -) + ;; + dhcp|tcpflags|arp_filter|routefilter|maclist|logmartians|sourceroute|blacklist|proxyarp|nosmurfs|upnp|-) + ;; + norfc1918) + cat >> $RESTOREBASE << __EOF__ + +${INDENT}addr=\$(ip -f inet addr show $interface 2> /dev/null | grep inet | head -n1) +${INDENT}if [ -n "\$addr" ]; then +${INDENT} addr=\$(echo \$addr | sed 's/inet //;s/\/.*//;s/ peer.*//') +${INDENT} for network in 10.0.0.0/8 176.16.0.0/12 192.168.0.0/16; do +${INDENT} if in_network \$addr \$network; then +${INDENT} fatal_error "The 'norfc1918' option has been specified on an interface with an RFC 1918 address. Interface:$interface" +${INDENT} fi +${INDENT} done +${INDENT}fi + +__EOF__ + ;; + arp_ignore=*) + eval ${iface}_arp_ignore=${option#*=} + ;; + arp_ignore) + eval ${iface}_arp_ignore=1 + ;; + detectnets) + [ -n "$wildcard" ] && \ + startup_error "The \"detectnets\" option may not be used with a wild-card interface" + [ -n $EXPORT ] && \ + startup_error "'detectnets' not permitted with the -e run-line option" + ;; + routeback) + [ -n "$z" ] || startup_error "The routeback option may not be specified on a multi-zone interface" + ;; + *) + error_message "WARNING: Invalid option ($option) in record \"$r\"" + ;; + esac + done + done < $TMP_DIR/interfaces + + [ -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 +{ + verify_mark1() + { + [ $1 -lt 256 ] + } + + verify_mark2() + { + verify_mark1 $1 2> /dev/null + } + + verify_mark2 $1 || fatal_error "Invalid Mark or Mask value: $1" +} + +# +# Process the providers file +# +setup_providers() +{ + local table number mark duplicate interface gateway options provider address copy route loose addresses rulenum pref echobin=$(mywhich echo) balance + + copy_table() { + cat >> $RESTOREBASE << __EOF__ +${INDENT} ip route show table $duplicate | while read net route; do +${INDENT} case \$net in +${INDENT} default|nexthop) +${INDENT} ;; +${INDENT} *) +${INDENT} run_ip route add table $number \$net \$route" +${INDENT} ;; +${INDENT} esac +${INDENT} done +__EOF__ + } + + copy_and_edit_table() { + cat >> $RESTOREBASE << __EOF__ +${INDENT} ip route show table $duplicate | while read net route; do +${INDENT} case \$net in +${INDENT} default|nexthop) +${INDENT} ;; +${INDENT} *) +${INDENT} case \$(find_device \$route) in +${INDENT} `echo $copy\) | sed 's/ /|/g'` +${INDENT} run_ip route add table $number \$net \$route +${INDENT} ;; +${INDENT} esac +${INDENT} ;; +${INDENT} esac +${INDENT} done + +__EOF__ + } + + add_a_provider() { + local t n iface option + + [ -n "$MANGLE_ENABLED" ] || fatal_error "Providers require mangle support in your kernel and iptables" + + 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 + + save_command " qt ip route flush table $number" + + if [ "x${duplicate:=-}" != x- ]; then + if [ "x${copy:=-}" != "x-" ]; then + if [ "x${copy}" = xnone ]; then + copy=$interface + else + copy="$interface $(separate_list $copy)" + fi + copy_and_edit_table + else + copy_table + fi + fi + + if [ "x$gateway" = xdetect ] ; then + cat >> $RESTOREBASE << __EOF__ +${INDENT} gateway=\$(detect_gateway $interface) + +${INDENT} if [ -n "\$gateway" ]; then +${INDENT} run_ip route replace \$gateway src \$(find_first_interface_address $interface) dev $interface table $number +${INDENT} run_ip route add default via \$gateway dev $interface table $number +${INDENT} else +${INDENT} fatal_error "Unable to detect the gateway through interface $interface" +${INDENT} fi + +__EOF__ + fi + + if [ x${mark} != x- ]; then + verify_mark $mark + + eval ${table}_mark=$mark + + save_command " qt ip rule del fwmark $mark" + save_command " run_ip rule add fwmark $mark pref $((10000 + $mark)) table $number" + fi + + loose= + + for option in $(separate_list $options); do + case $option in + -) + ;; + track) + list_search $interface $ROUTEMARK_INTERFACES && \ + fatal_error "Interface $interface is tracked through an earlier provider" + iface=$(chain_base $interface) + [ x${mark} = x- ] && fatal_error "The 'track' option requires a numeric value in the MARK column - Provider \"$provider\"" + eval ${iface}_routemark=$mark + ROUTEMARK_INTERFACES="$ROUTEMARK_INTERFACES $interface" + ;; + balance=*) + balance=yes + save_command " DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via \$gateway dev $interface weight ${option#*=}\"" + ;; + balance) + balance=yes + save_command " DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via \$gateway dev $interface weight 1\"" + ;; + loose) + loose=Yes + ;; + *) + error_message " WARNING: Invalid option ($option) ignored in provider \"$provider\"" + ;; + esac + done + + rulenum=0 + + if [ -z "$loose" ]; then + cat >> $RESTOREBASE << __EOF__ + +${INDENT} rulenum=0 + +${INDENT} find_interface_addresses $interface | while read address; do +${INDENT} qt ip rule del from \$address +${INDENT} pref=\$((20000 + \$rulenum * 1000 + $number )) +${INDENT} rulenum=\$((\$rulenum + 1)) +${INDENT} run_ip rule add from \$address pref \$pref table $number +${INDENT} done + +__EOF__ + else + cat >> $RESTOREBASE << __EOF__ + +${INDENT} find_interface_addresses $interface | while read address; do +${INDENT} qt ip rule del from \$address +${INDENT} done + +__EOF__ + fi + } + + strip_file providers $1 + + if [ -s $TMP_DIR/providers ]; then + DEFAULT_ROUTE= + balance= + + progress_message2 "$DOING $1..." + save_progress_message "Adding Providers..." + save_command "if [ -z \"\$NOROUTES\" ]; then" + save_command " DEFAULT_ROUTE=" + + 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" + add_a_provider + PROVIDERS="$PROVIDERS $table" + progress_message " Provider $provider $DONE" + done < $TMP_DIR/providers + + if [ -n "$PROVIDERS" ]; then + if [ -n "$balance" ]; then + save_command " run_ip route replace default scope global \$DEFAULT_ROUTE" + save_command " progress_message Default route \$DEFAULT_ROUTE Added" + fi + + cat >> $RESTOREBASE << __EOF__ +${INDENT} cat > /etc/iproute2/rt_tables <> $RESTOREBASE << __EOF__ +${INDENT} \${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables +__EOF__ + done + fi + + save_command " run_ip route flush cache" + save_command "fi" + save_command "" + fi +} + +# +# Validate the zone names and options in the hosts file +# +validate_hosts_file() { + local z hosts options r interface host option port ports + + check_bridge_port() + { + 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" + } + + 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\"" + + case $hosts in + *:*) + + interface=${hosts%%:*} + iface=$(chain_base $interface) + + list_search $interface $ALL_INTERFACES || \ + startup_error "Unknown interface ($interface) in record \"$r\"" + + hosts=${hosts#*:} + ;; + *) + startup_error "Invalid HOST(S) column contents: $hosts" + ;; + esac + + ports=\$${iface} + eval zports=\$${z}_ports + + 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%%:*} + ;; + *.*.*.*) + ;; + +*) + eval ${z}_is_complex=Yes + ;; + *) + known_interface $host && \ + startup_error "Bridged interfaces may not be defined in /etc/shorewall/interfaces: $host" + check_bridge_port $host + ;; + esac + else + case $host in + +*) + eval ${z}_is_complex=Yes + ;; + esac + fi + + for option in $(separate_list $options) ; do + case $option in + norfc1918|blacklist|maclist|tcpflags|nosmurfs|-) + ;; + 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\" + ;; + *) + error_message "WARNING: Invalid option ($option) in record \"$r\"" + ;; + esac + done + done + + [ -n "$ports" ] && eval ${z}_ports=\"$zports\" + + done < $TMP_DIR/hosts + + [ -n "$ALL_PORTS" ] && progress_message2 " Bridge ports are: $ALL_PORTS" +} + +# +# 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 +# +mac_match() # $1 = MAC address formated as described above +{ + echo "--match mac --mac-source $(echo $1 | sed 's/~//;s/-/:/g')" +} + +# +# validate the policy file +# +validate_policy() +{ + local clientwild + local serverwild + local zone + local zone1 + local pc + local chain + local policy + local loglevel + local synparams + + print_policy() # $1 = source zone, $2 = destination zone + { + [ $1 = $2 ] || \ + [ $1 = all ] || \ + [ $2 = all ] || \ + progress_message " Policy for $1 to $2 is $policy using chain $chain" + } + + ALL_POLICY_CHAINS= + + for zone in $ZONES $FW; do + chain=${zone}2${zone} + eval ${chain}_is_policy=Yes + eval ${chain}_is_optional=Yes + eval ${chain}_policy=ACCEPT + eval ${chain}_policychain=$chain + ALL_POLICY_CHAINS="$ALL_POLICY_CHAINS $chain" + done + + strip_file policy + + while read client server policy loglevel synparams; do + expandv client server policy loglevel synparams + + clientwild= + serverwild= + + case "$client" in + all|ALL) + clientwild=Yes + ;; + *) + if ! validate_zone $client; then + startup_error "Undefined zone $client" + fi + esac + + case "$server" in + all|ALL) + serverwild=Yes + ;; + *) + if ! validate_zone $server; then + startup_error "Undefined zone $server" + fi + esac + + case $policy in + ACCEPT|REJECT|DROP|CONTINUE|QUEUE) + ;; + 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\"" + ;; + *) + startup_error "Invalid policy $policy" + ;; + esac + + chain=${client}2${server} + + if is_policy_chain $chain ; then + if eval test \$${chain}_is_optional = Yes ; then + eval ${chain}_is_optional= + else + startup_error "Duplicate policy: $client $server $policy" + fi + fi + + [ "x$loglevel" = "x-" ] && loglevel= + [ "x$synparams" = "x-" ] && synparams= + + [ $policy = NONE ] || ALL_POLICY_CHAINS="$ALL_POLICY_CHAINS $chain" + + 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 + for zone in $ZONES $FW all; do + for zone1 in $ZONES $FW all; do + eval pc=\$${zone}2${zone1}_policychain + + if [ -z "$pc" ]; then + eval ${zone}2${zone1}_policychain=$chain + eval ${zone}2${zone1}_policy=$policy + print_policy $zone $zone1 + fi + done + done + else + for zone in $ZONES $FW all; do + eval pc=\$${zone}2${server}_policychain + + if [ -z "$pc" ]; then + eval ${zone}2${server}_policychain=$chain + eval ${zone}2${server}_policy=$policy + print_policy $zone $server + fi + done + fi + elif [ -n "$serverwild" ]; then + for zone in $ZONES $FW all; do + eval pc=\$${client}2${zone}_policychain + + if [ -z "$pc" ]; then + eval ${client}2${zone}_policychain=$chain + eval ${client}2${zone}_policy=$policy + print_policy $client $zone + fi + done + else + eval ${chain}_policychain=${chain} + print_policy $client $server + fi + + done < $TMP_DIR/policy +} + +# +# 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" -a "x${bcast}" != "x-" ]; then + echo $(separate_list $bcast) + fi + done +} + +# +# Find interfaces with BROADCAST=detect -- Only returns information if we are compiling a script +# +find_bcastdetect_interfaces() { + for interface in $ALL_INTERFACES; do + eval bcast=\$$(chain_base $interface)_broadcast + [ "x$bcast" = "xdetect" ] && echo $interface + done +} + +# +# Find interfaces that have the passed option specified +# +find_interfaces_by_option() # $1 = option +{ + for interface in $ALL_INTERFACES; do + eval options=\$$(chain_base $interface)_options + list_search $1 $options && echo $interface + done +} + +# +# 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 +} + +# +# Find hosts with the passed option +# +find_hosts_by_option() # $1 = option +{ + local ignore hosts interface address addresses options ipsec= list + + while read ignore hosts options; do + expandv options + list=$(separate_list $options) + if list_search $1 $list; then + list_search ipsec $list && ipsec=ipsec || ipsec=none + expandv hosts + interface=${hosts%%:*} + addresses=${hosts#*:} + for address in $(separate_list $addresses); do + echo ${ipsec}^$interface:$address + done + fi + done < $TMP_DIR/hosts + + for interface in $ALL_INTERFACES; do + interface_has_option $interface $1 && \ + echo none^${interface}:0.0.0.0/0 + done +} + +# +# Flush and delete all user-defined chains in the filter table +# +deleteallchains() { + run_iptables -F + run_iptables -X +} + +# +# Set /proc/sys/net/ipv4/ip_forward based on $IP_FORWARDING +# +setup_forwarding() { + + save_progress_message "Setting up IP Forwarding..." + + case "$IP_FORWARDING" in + [Oo][Nn]) + save_command "echo 1 > /proc/sys/net/ipv4/ip_forward" + progress_message2 "IP Forwarding Enabled" + ;; + [Oo][Ff][Ff]) + save_command "echo 0 > /proc/sys/net/ipv4/ip_forward" + progress_message2 "IP Forwarding Disabled!" + ;; + esac +} + +# +# Process the routestopped file either adding or deleting rules +# +process_routestopped() # $1 = command +{ + local hosts= interface host host1 options networks source= dest= matched + + 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 + error_message "WARNING: Duplicate routestopped option ignored: routeback" + 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 + ;; + 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 + ;; + critical) + ;; + *) + error_message "WARNING: Unknown routestopped option ignored: $option" + ;; + esac + done + fi + + done < $TMP_DIR/routestopped + + + for host in $hosts; do + interface=${host%:*} + networks=${host#*:} + run_iptables $1 INPUT -i $interface $(source_ip_range $networks) -j ACCEPT + [ -z "$ADMINISABSENTMINDED" -o $COMMAND != stop ] && \ + run_iptables $1 OUTPUT -o $interface $(dest_ip_range $networks) -j ACCEPT + + 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 + + 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 + done +} + +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 + fi + done < $TMP_DIR/routestopped + + if [ -n "$criticalhosts" ]; then + CRITICALHOSTS=$criticalhosts + progress_message "Critical Hosts are:$CRITICALHOSTS" + fi + +} + +# +# 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#*:} + do_iptables -A INPUT -i $interface $(source_ip_range $networks) -j ACCEPT + do_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#*:} + do_iptables -D INPUT -i $interface $(source_ip_range $networks) -j ACCEPT + do_iptables -D OUTPUT -o $interface $(dest_ip_range $networks) -j ACCEPT + done +} + +# +# Set up ipsec tunnels +# +setup_tunnels() # $1 = name of tunnels file +{ + local inchain + local outchain + + + setup_one_ipsec() # $1 = gateway $2 = Tunnel Kind $3 = gateway zones + { + 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 + + 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 + + if [ -z "$noah" ]; then + run_iptables -A $inchain -p 51 $(source_ip_range $1) -j ACCEPT + run_iptables -A $outchain -p 51 $(dest_ip_range $1) -j ACCEPT + fi + + run_iptables -A $outchain -p udp $(dest_ip_range $1) --dport 500 $options + + if [ $kind = ipsec ]; then + run_iptables -A $inchain -p udp $(source_ip_range $1) --dport 500 $options + else + 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 + fi + + for z in $(separate_list $3); do + if validate_zone $z; then + addrule ${FW}2${z} -p udp --dport 500 $options + if [ $kind = ipsec ]; then + addrule ${z}2${FW} -p udp --dport 500 $options + else + addrule ${z}2${FW} -p udp --dport 500 $options + addrule ${z}2${FW} -p udp --dport 4500 $options + fi + else + fatal_error "Invalid gateway zone ($z) -- Tunnel \"$tunnel\"" + fi + done + + progress_message " IPSEC tunnel to $gateway defined." + } + + setup_one_other() # $1 = TYPE, $2 = gateway, $3 = protocol + { + addrule2 $inchain -p $3 $(source_ip_range $2) -j ACCEPT + addrule2 $outchain -p $3 $(dest_ip_range $2) -j ACCEPT + + progress_message " $1 tunnel to $2 defined." + } + + setup_pptp_client() # $1 = gateway + { + 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 + + progress_message " PPTP tunnel to $1 defined." + } + + setup_pptp_server() # $1 = gateway + { + 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 + + progress_message " PPTP server defined." + } + + setup_one_openvpn() # $1 = gateway, $2 = kind[:port] + { + local protocol=udp + local p=1194 + + case $2 in + *:*:*) + protocol=${2%:*} + protocol=${protocol#*:} + p=${2##*:} + ;; + *:tcp|*:udp|*:TCP|*:UDP) + protocol=${2#*:} + ;; + *:*) + p=${2#*:} + ;; + esac + + addrule2 $inchain -p $protocol $(source_ip_range $1) --dport $p -j ACCEPT + addrule2 $outchain -p $protocol $(dest_ip_range $1) --dport $p -j ACCEPT + + progress_message " OPENVPN tunnel to $1:$protocol:$p defined." + } + + setup_one_openvpn_server() # $1 = gateway, $2 = kind[:port] + { + local protocol=udp + local p=1194 + + case $2 in + *:*:*) + protocol=${2%:*} + protocol=${protocol#*:} + p=${2##*:} + ;; + *:tcp|*:udp|*:TCP|*:UDP) + protocol=${2#*:} + ;; + *:*) + p=${2#*:} + ;; + esac + + addrule2 $inchain -p $protocol $(source_ip_range $1) --dport $p -j ACCEPT + addrule2 $outchain -p $protocol $(dest_ip_range $1) --sport $p -j ACCEPT + + progress_message " OPENVPN server tunnel from $1:$protocol:$p defined." + } + + setup_one_openvpn_client() # $1 = gateway, $2 = kind[:port] + { + local protocol=udp + local p=1194 + + case $2 in + *:*:*) + protocol=${2%:*} + protocol=${protocol#*:} + p=${2##*:} + ;; + *:tcp|*:udp|*:TCP|*:UDP) + protocol=${2#*:} + ;; + *:*) + p=${2#*:} + ;; + esac + + addrule2 $inchain -p $protocol $(source_ip_range $1) --sport $p -j ACCEPT + addrule2 $outchain -p $protocol $(dest_ip_range $1) --dport $p -j ACCEPT + + progress_message " OPENVPN client tunnel to $1:$protocol:$p defined." + } + + setup_one_generic() # $1 = gateway, $2 = kind:protocol[:port] + { + local protocol + local p= + + case $2 in + *:*:*) + p=${2##*:} + protocol=${2%:*} + protocol=${protocol#*:} + ;; + *:*) + protocol=${2#*:} + ;; + *) + protocol=udp + p=5000 + ;; + esac + + p=${p:+--dport $p} + + addrule2 $inchain -p $protocol $(source_ip_range $1) $p -j ACCEPT + addrule2 $outchain -p $protocol $(dest_ip_range $1) $p -j ACCEPT + + progress_message " GENERIC tunnel to $1:$p defined." + } + + strip_file tunnels $1 + + while read kind z gateway z1; do + expandv kind z gateway z1 + tunnel="$(echo $kind $z $gateway $z1)" + if validate_zone $z; then + inchain=${z}2${FW} + outchain=${FW}2${z} + gateway=${gateway:-0.0.0.0/0} + case $kind in + ipsec|IPSEC|ipsec:*|IPSEC:*) + setup_one_ipsec $gateway $kind $z1 + ;; + ipsecnat|IPSECNAT|ipsecnat:*|IPSECNAT:*) + setup_one_ipsec $gateway $kind $z1 + ;; + ipip|IPIP) + setup_one_other IPIP $gateway 4 + ;; + gre|GRE) + setup_one_other GRE $gateway 47 + ;; + 6to4|6TO4) + setup_one_other 6to4 $gateway 41 + ;; + pptpclient|PPTPCLIENT) + setup_pptp_client $gateway + ;; + pptpserver|PPTPSERVER) + setup_pptp_server $gateway + ;; + openvpn|OPENVPN|openvpn:*|OPENVPN:*) + setup_one_openvpn $gateway $kind + ;; + openvpnclient|OPENVPNCLIENT|openvpnclient:*|OPENVPNCLIENT:*) + setup_one_openvpn_client $gateway $kind + ;; + openvpnserver|OPENVPNSERVER|openvpnserver:*|OPENVPNSERVER:*) + setup_one_openvpn_server $gateway $kind + ;; + generic:*|GENERIC:*) + setup_one_generic $gateway $kind + ;; + *) + error_message "WARNING: Tunnels of type $kind are not supported:" \ + "Tunnel \"$tunnel\" Ignored" + ;; + esac + else + error_message "ERROR: Invalid gateway zone ($z)" \ + " -- Tunnel \"$tunnel\" Ignored" + fi + done < $TMP_DIR/tunnels +} + +# +# Process the ipsec information in the zones file +# +setup_ipsec() { + local zone using_ipsec= + # + # 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 "" + { + for z in $ZONES; do + case $2 in + _in) + set_mss1 ${zone}2${z} $1 + ;; + _out) + set_mss1 ${z}2${zone} $1 + ;; + *) + set_mss1 ${z}2${zone} $1 + set_mss1 ${zone}2${z} $1 + ;; + esac + done +} + + 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 + mss=[0-9]*) set_mss $val $1 ;; + 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 + [ -n "$POLICY_MATCH" ] || fatal_error "Your kernel and/or iptables does not support policy match" + eval ${zone}_is_complex=Yes + eval ${zone}_ipsec${1}_options=\"${newoptions# }\" + fi + } + + case $IPSECFILE in + zones) + f=zones + progress_message "Setting up IPSEC..." + ;; + *) + f=$IPSECFILE + strip_file $f + progress_message "$DOING $f..." + using_ipsec=Yes + ;; + esac + + while read zone type options in_options out_options mss; do + expandv zone type options in_options out_options mss + + if [ -n "$using_ipsec" ]; then + validate_zone1 $zone || fatal_error "Unknown zone: $zone" + fi + + 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 + eval ${zone}_type=ipsec4 + ;; + *) + fatal_error "Invalid IPSEC column contents" + ;; + esac + fi + + do_options "" $options + do_options "_in" $in_options + do_options "_out" $out_options + fi + + done < $TMP_DIR/$f +} + +## +# Setup Proxy ARP +# +setup_proxy_arp() { + + local setlist= resetlist= + + print_error() { + error_message "Invalid value for HAVEROUTE - ($haveroute)" + error_message "Entry \"$address $interface $external $haveroute\" ignored" + } + + 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\"" + } + + setup_one_proxy_arp() { + + case $haveroute in + [Nn][Oo]) + haveroute= + ;; + [Yy][Ee][Ss]) + ;; + *) + if [ -n "$haveroute" ]; then + print_error + return + fi + ;; + esac + + case $persistent in + [Nn][Oo]) + persistent= + ;; + [Yy][Ee][Ss]) + [ -z "$haveroute" ] || print_warning + ;; + *) + if [ -n "$persistent" ]; then + print_error1 + return + fi + ;; + esac + + if [ -z "$haveroute" ]; then + save_command "[ -n \"\$NOROUTES\" ] || run_ip route replace $address dev $interface" + [ -n "$persistent" ] && haveroute=yes + fi + + cat >> $RESTOREBASE << __EOF__ +${INDENT}if ! arp -i $external -Ds $address $external pub; then +${INDENT} fatal_error "Command \"arp -i $external -Ds $address $external pub\" failed" +${INDENT}fi + +${INDENT}progress_message " Host $address connected to $interface added to ARP on $external" + +__EOF__ + echo $address $interface $external $haveroute >> $STATEDIR/proxyarp + + progress_message " Host $address connected to $interface added to ARP on $external" + } + + > $STATEDIR/proxyarp + + save_progress_message "Setting up Proxy ARP..." + + while read address interface external haveroute persistent; do + expandv address interface external haveroute persistent + list_search $interface $setlist || setlist="$setlist $interface" + list_search $external $resetlist || list_search $external $setlist || resetlist="$resetlist $external" + setup_one_proxy_arp + done < $TMP_DIR/proxyarp + + for interface in $resetlist; do + list_search $interface $setlist || \ + save_command "echo 0 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" + done + + for interface in $setlist; do + save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" + done + + interfaces=$(find_interfaces_by_option proxyarp) + + for interface in $interfaces; do + if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ] ; then + save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" + progress_message " Enabled proxy ARP on $interface" + else + error_message "WARNING: Unable to enable proxy ARP on $interface" + fi + done + +} + +# +# Set up MAC Verification +# +setup_mac_lists() { + local interface + local mac + local addresses + local address + local chain + local chain1 + local macpart + local blob + local hosts + local ipsec + local policy= + + create_mac_chain() + { + case $MACLIST_TABLE in + filter) + createchain $1 no + ;; + *) + createmanglechain $1 + ;; + esac + } + + have_mac_chain() + { + local result + + case $MACLIST_TABLE in + filter) + havechain $1 && result=0 || result=1 + ;; + *) + havemanglechain $1 && result=0 || result=1 + ;; + esac + + return $result + } + # + # Generate the list of interfaces having MAC verification + # + maclist_interfaces= + + for hosts in $maclist_hosts; do + hosts=${hosts#*^} + interface=${hosts%%:*} + if ! list_search $interface $maclist_interfaces; then\ + if [ -z "$maclist_interfaces" ]; then + maclist_interfaces=$interface + else + maclist_interfaces="$maclist_interfaces $interface" + fi + fi + done + + progress_message "Setting up MAC Verification on $maclist_interfaces..." + # + # Create chains. + # + for interface in $maclist_interfaces; do + chain=$(mac_chain $interface) + create_mac_chain $chain + # + # If we're using the mangle table and the interface is DHCP-enabled then we need to accept DHCP broadcasts from 0.0.0.0 + # + if [ $MACLIST_TABLE = mangle ] && interface_has_option $interface dhcp; then + run_iptables -t mangle -A $chain -s 0.0.0.0 -d 255.255.255.255 -p udp --dport 67:68 -j RETURN + fi + + if [ -n "$MACLIST_TTL" ]; then + chain1=$(macrecent_target $interface) + 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 + fi + done + + # + # Process the maclist file producing the verification rules + # + while read disposition interface mac addresses; do + expandv disposition interface mac addresses + + case $disposition in + ACCEPT) + disposition=RETURN + ;; + REJECT) + [ $MACLIST_TABLE = mangle ] && fatal_error "DISPOSITION = REJECT is incompatible with MACLIST_TABLE=mangle" + ;; + DROP) + ;; + *) + addresses="$mac" + mac="$interface" + interface="$disposition" + disposition=RETURN + ;; + esac + + physdev_part= + + if [ -n "$BRIDGING" ]; then + case $interface in + *:*) + physdev_part="-m physdev --physdev-in ${interface#*:}" + interface=${interface%:*} + ;; + esac + fi + + [ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface) + + if ! have_mac_chain $chain ; then + fatal_error "No hosts on $interface have the maclist option specified" + fi + + if [ x${mac:=-} = x- ]; then + if [ -z "$addresses" ]; then + fatal_error "You must specify a MAC address or an IP address" + else + mac= + fi + else + macpart=$(mac_match $mac) + fi + + if [ -z "$addresses" ]; then + run_iptables -t $MACLIST_TABLE -A $chain $macpart $physdev_part -j $disposition + else + for address in $(separate_list $addresses) ; do + run_iptables2 -t $MACLIST_TABLE -A $chain $macpart -s $address $physdev_part -j $disposition + done + fi + done < $TMP_DIR/maclist + # + # Must take care of our own broadcasts and multicasts then terminate the verification + # chains + # + for interface in $maclist_interfaces; do + + [ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface) + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}blob=\$(ip link show $interface 2> /dev/null) + +${INDENT}[ -z "\$blob" ] && \ +${INDENT} fatal_error "Interface $interface must be up before Shorewall can start" + +${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do +${INDENT} address=\${address%/*} +${INDENT} if [ -n "\$broadcast" ]; then +${INDENT} run_iptables -t $MACLIST_TABLE -A $chain -s \$address -d \$broadcast -j RETURN +${INDENT} fi +${INDENT}done + +__EOF__ + + if [ -n "$MACLIST_LOG_LEVEL" ]; then + log_rule_limit $MACLIST_LOG_LEVEL $chain $(mac_chain $interface) $MACLIST_DISPOSITION "$LOGLIMIT" "" -A -t $MACLIST_TABLE + fi + + run_iptables -t $MACLIST_TABLE -A $chain -j $maclist_target + done + # + # Generate jumps from the input and forward chains + # + for hosts in $maclist_hosts; do + ipsec=${hosts%^*} + hosts=${hosts#*^} + [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= + interface=${hosts%%:*} + hosts=${hosts#*:} + 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 + ;; + *) + run_iptables -t mangle -A PREROUTING -i $interface $(match_source_hosts $hosts) -m state --state NEW \ + $policy -j $(mac_chain $interface) + ;; + esac + done +} + +# +# Set up SYN flood protection +# +setup_syn_flood_chain () + # $1 = policy chain + # $2 = synparams + # $3 = loglevel +{ + local chain=@$1 + local limit=$2 + local limit_burst= + + case $limit in + *:*) + limit_burst="--limit-burst ${limit#*:}" + limit=${limit%:*} + ;; + esac + + run_iptables -N $chain + run_iptables -A $chain -m limit --limit $limit $limit_burst -j RETURN + [ -n "$3" ] && \ + log_rule_limit $3 $chain $chain DROP "-m limit --limit 5/min --limit-burst 5" "" "" + run_iptables -A $chain -j DROP +} + +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 +} + +# +# Delete existing Proxy ARP +# +delete_proxy_arp() { + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f /var/lib/shorewall/proxyarp ]; then +${INDENT} while read address interface external haveroute; do +${INDENT} qt arp -i \$external -d \$address pub +${INDENT} [ -z "\$haveroute" -a -z "\$NOROUTE" ] && qt ip route del \$address dev \$interface +${INDENT} done < /var/lib/shorewall/proxyarp + +${INDENT} rm -f {/var/lib/shorewall}/nat +${INDENT}fi +__EOF__ + + [ -d $STATEDIR ] && touch $STATEDIR/proxyarp + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}for f in /proc/sys/net/ipv4/conf/*; do +${INDENT} [ -f \$f/proxy_arp ] && echo 0 > \$f/proxy_arp +${INDENT}done +${INDENT} +__EOF__ +} + +# +# Setup Static Network Address Translation (NAT) +# +setup_nat() { + local external= interface= internal= allints= localnat= policyin= policyout= + + validate_one() #1 = Variable Name, $2 = Column name, $3 = value + { + 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 + } + + do_one_nat() { + local add_ip_aliases=$ADD_IP_ALIASES iface=${interface%:*} + + if [ -n "$add_ip_aliases" ]; then + case $interface in + *:) + interface=${interface%:} + add_ip_aliases= + ;; + *) + [ -n "$RETAIN_ALIASES" ] || save_command qt ip addr del $external dev $iface + ;; + esac + else + interface=${interface%:} + fi + + validate_one allints "ALL INTERFACES" $allints + validate_one localnat "LOCAL" $localnat + + 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 + + [ -n "$localnat" ] && \ + run_iptables2 -t nat -A OUTPUT -d $external $policyout -j DNAT --to-destination $internal + + if [ -n "$add_ip_aliases" ]; then + list_search $external $ALIASES_TO_ADD || \ + ALIASES_TO_ADD="$ALIASES_TO_ADD $external $interface" + fi + } + # + # At this point, we're just interested in the network translation + # + > $STATEDIR/nat + + if [ -n "$POLICY_MATCH" ]; then + policyin="-m policy --pol none --dir in" + policyout="-m policy --pol none --dir out" + fi + + [ -n "$RETAIN_ALIASES" ] || save_progress_message "Setting up one-to-one NAT..." + + while read external interface internal allints localnat; do + expandv external interface internal allints localnat + + do_one_nat + + progress_message " Host $internal NAT $external on $interface" + done < $TMP_DIR/nat +} + +# +# Delete existing Static NAT +# +delete_nat() { + run_iptables -t nat -F + run_iptables -t nat -X + + [ -d $STATEDIR ] && touch $STATEDIR/nat + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}if [ -f /var/lib/shorewall/nat ]; then +${INDENT} while read external interface; do +${INDENT} qt ip addr del \$external dev \$interface +${INDENT} done < /var/lib/shorewall/nat +${INDENT} +${INDENT} rm -f {/var/lib/shorewall}/nat +${INDENT}fi + +__EOF__ +} + +# +# Setup Network Mapping (NETMAP) +# +setup_netmap() { + + while read type net1 interface net2 ; do + expandv type net1 interface net2 + + list_search $interface $ALL_INTERFACES || \ + 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 +} + +# +# Setup ECN disabling rules +# +setup_ecn() # $1 = file name +{ + local interfaces="" + local hosts= + local h + + strip_file ecn $1 + + progress_message2 "$DOING $1..." + + while read interface host; do + expandv interface host + list_search $interface $ALL_INTERFACES || \ + startup_error "Unknown interface $interface" + list_search $interface $interfaces || \ + interfaces="$interfaces $interface" + [ "x$host" = "x-" ] && host= + for h in $(separate_list ${host:-0.0.0.0/0}); do + hosts="$hosts $interface:$h" + done + done < $TMP_DIR/ecn + + if [ -n "$interfaces" ]; then + progress_message "Setting up ECN control on${interfaces}..." + + for interface in $interfaces; do + chain=$(ecn_chain $interface) + if havemanglechain $chain; then + flushmangle $chain + else + createmanglechain $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 + + for host in $hosts; do + interface=${host%:*} + h=${host#*:} + run_iptables -t mangle -A $(ecn_chain $interface) -p tcp $(dest_ip_range $h) -j ECN --ecn-tcp-remove + progress_message " ECN Disabled to $h through $interface" + done + fi +} + +# +# Set up an exclusion chain +# +build_exclusion_chain() # $1 = variable to store chain name into $2 = table, $3 = SOURCE exclusion list, $4 = DESTINATION exclusion list +{ + local c=excl_${EXCLUSION_SEQ} net + + EXCLUSION_SEQ=$(( $EXCLUSION_SEQ + 1 )) + + run_iptables -t $2 -N $c + + for net in $(separate_list $3); do + run_iptables -t $2 -A $c $(source_ip_range $net) -j RETURN + done + + for net in $(separate_list $4); do + run_iptables -t $2 -A $c $(dest_ip_range $net) -j RETURN + done + + case $2 in + filter) + eval exists_${c}=Yes + ;; + nat) + eval exists_nat_${c}=Yes + ;; + esac + + eval $1=$c +} + +# +# Arne Bernin's 'tc4shorewall' +# +setup_traffic_shaping() +{ + local mtu r2q tc_all_devices device mark rate ceil prio options devfile=$(find_file tcdevices) classfile=$(find_file tcclasses) devnum=1 + mtu=1500 + r2q=10 + + ensure_and_save_tc() { + run_tc $@ + } + + 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() { + progress_message2 "Validating $devfile..." + 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() { + progress_message2 "Validating $classfile..." + 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) + save_command qt tc qdisc del dev $device root + save_command qt tc qdisc del dev $device ingress + ensure_and_save_tc qdisc add dev $device root handle $devnum: htb default 1$defmark + ensure_and_save_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $outband + ensure_and_save_tc qdisc add dev $device handle ffff: ingress + ensure_and_save_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 + eval $(chain_base $device)_devnum=$devnum + devnum=$(($devnum + 1)) + } + + add_tc_class() { + local full classid + 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 + + eval devnum=\$$(chain_base $device)_devnum + classid=$devnum:1$mark + + [ -n "$devnum" ] || fatal_error "Device $device not defined in $devfile" + + ensure_and_save_tc class add dev $device parent $devnum:1 classid $classid htb rate $rate ceil $ceil prio $prio quantum $(calculate_quantum $rate) + ensure_and_save_tc qdisc add dev $device parent $classid handle 1$mark: sfq perturb 10 + # add filters + if [ -n "$CLASSIFY_TARGET" ]; then + run_iptables -t mangle -A tcpost -o $device -m mark --mark $mark -j CLASSIFY --set-class $classid + else + ensure_and_save_tc filter add dev $device protocol ip parent $devnum:0 prio 1 handle $mark fw classid $classid + fi + #options + list_search "tcp-ack" $options && ensure_and_save_tc filter add dev $device parent $devnum: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 $classid + list_search "tos-minimize-delay" $options && ensure_and_save_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid $classid + list_search "tos-minimize-cost" $options && ensure_and_save_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos 0x02 0xff flowid $classid + list_search "tos-maximize-troughput" $options && ensure_and_save_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos 0x08 0xff flowid $classid + list_search "tos-minimize-reliability" $options && ensure_and_save_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos 0x04 0xff flowid $classid + list_search "tos-normal-service" $options && ensure_and_save_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos 0x00 0xff flowid $classid + # tcp + } + + strip_file tcdevices $devfile + strip_file tcclasses $classfile + + validate_tcdevices_file + validate_tcclasses_file + + if [ -s $TMP_DIR/tcdevices ]; then + save_progress_message "Setting up Traffic Control..." + progress_message2 "$DOING $devfile..." + + 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 $DONE." + done < $TMP_DIR/tcdevices + fi + + if [ -s $TMP_DIR/tcclasses ]; then + progress_message2 "$DOING $classfile..." + + 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 $DONE." + done < $TMP_DIR/tcclasses + fi +} + +# +# Process a TC Rule - $MARKING_CHAIN is assumed to contain the name of the +# default marking chain +# +process_tc_rule() +{ + chain=$MARKING_CHAIN target="MARK --set-mark" marktest= + + verify_designator() { + [ "$chain" = tcout ] && \ + fatal_error "Chain designator not allowed when source is \$FW; rule \"$rule\"" + chain=$1 + mark="${mark%:*}" + } + + do_ipp2p() + { + [ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\"" + [ "x$port" = "x-" ] && port="ipp2p" + + case $proto in + *:*) + proto=${proto#*:} + ;; + *) + proto=tcp + ;; + esac + + r="${r}-p $proto -m ipp2p --${port} " + } + + add_a_tc_rule() { + r= + + if [ "x$source" != "x-" ]; then + case $source in + $FW:*) + [ $chain = tcpost ] || chain=tcout + r="$(source_ip_range ${source#*:}) " + ;; + *.*.*|+*|!+*) + r="$(source_ip_range $source) " + ;; + ~*) + r="$(mac_match $source) " + ;; + $FW) + [ $chain = tcpost ] || chain=tcout + ;; + *) + verify_interface $source || fatal_error "Unknown interface $source in rule \"$rule\"" + r="$(match_source_dev $source) " + ;; + esac + fi + + if [ "x${user:--}" != "x-" ]; then + + [ "$chain" != tcout ] && \ + fatal_error "Invalid use of a user/group: rule \"$rule\"" + + r="$r-m owner" + + case "$user" in + *+*) + r="$r --cmd-owner ${user#*+} " + user=${user%+*} + ;; + esac + + case "$user" in + *:*) + temp="${user%:*}" + [ -n "$temp" ] && r="$r --uid-owner $temp " + temp="${user#*:}" + [ -n "$temp" ] && r="$r --gid-owner $temp " + ;; + *) + [ -n "$user" ] && r="$r --uid-owner $user " + ;; + esac + fi + + [ -n "$marktest" ] && r="${r}-m ${marktest}--mark $testval " + + if [ "x$dest" != "x-" ]; then + case $dest in + *.*.*|+*|!+*) + r="${r}$(dest_ip_range $dest) " + ;; + *) + [ "$chain" = tcpre ] && fatal_error "Destination interface is not allowed in the PREROUTING chain" + verify_interface $dest || fatal_error "Unknown interface $dest in rule \"$rule\"" + r="${r}$(match_dest_dev $dest) " + ;; + esac + fi + + if [ "x${length:=-}" != "x-" ]; then + [ -n "$LENGTH_MATCH" ] || fatal_error "Your kernel and/or iptables does not have length match support. Rule: \"$rule\"" + r="${r}-m length --length ${length} " + fi + + multiport= + + case $proto in + ipp2p|IPP2P|ipp2p:*|IPP2P:*) + do_ipp2p + ;; + icmp|ICMP|1) + r="${r}-p icmp " + [ "x$port" = "x-" ] || r="${r}--icmp-type $port" + ;; + *) + [ "x$proto" = "x-" ] && proto=all + [ "x$proto" = "x" ] && proto=all + [ "$proto" = "all" ] || r="${r}-p $proto " + [ "x$port" = "x-" ] || r="${r}--dport $port " + ;; + esac + + [ "x$sport" = "x-" ] || r="${r}--sport $sport " + + 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 + + } + + if [ "$mark" != "${mark%:*}" ]; then + case "${mark#*:}" in + p|P) + verify_designator tcpre + ;; + cp|CP) + verify_designator tcpre + target="CONNMARK --set-mark" + ;; + f|F) + verify_designator tcfor + ;; + cf|CF) + verify_designator tcfor + target="CONNMARK --set-mark" + ;; + c|C) + target="CONNMARK --set-mark" + mark=${mark%:*} + ;; + *) + chain=tcpost + target="CLASSIFY --set-class" + ;; + esac + + fi + + case $mark in + SAVE) + target="CONNMARK --save-mark --mask 255" + mark= + ;; + SAVE/*) + target="CONNMARK --save-mark --mask" + mark=${mark#*/} + verify_mark $mark + ;; + RESTORE) + target="CONNMARK --restore-mark --mask 255" + mark= + ;; + RESTORE/*) + target="CONNMARK --restore-mark --mask" + mark=${mark#*/} + verify_mark $mark + ;; + CONTINUE) + target=RETURN + mark= + ;; + *) + if [ "$chain" != tcpost ]; then + verify_mark $mark + fi + ;; + esac + + case $testval in + -) + ;; + !*:C) + marktest="connmark ! " + testval=${testval%:*} + testval=${testval#!} + ;; + *:C) + marktest="connmark " + testval=${testval%:*} + ;; + !*) + marktest="mark ! " + testval=${testval#!} + ;; + *) + [ -n "$testval" ] && marktest="mark " + ;; + esac + + if [ -n "$marktest" ] ; then + case $testval in + */*) + verify_mark ${testval%/*} + verify_mark ${testval#*/} + ;; + *) + verify_mark $testval + testval=$testval/255 + ;; + esac + fi + + 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 + + for source in $(separate_list $sources); do + for dest in $(separate_list $dests); do + for port in $(separate_list ${ports:=-}); do + for sport in $(separate_list ${sports:=-}); do + add_a_tc_rule + done + done + done + done + + progress_message " TC Rule \"$rule\" $DONE" +} + +# +# Setup queuing and classes +# +setup_tc1() { + # + # Create the TC mangle chains + # + + createmanglechain tcpre + createmanglechain tcfor + createmanglechain tcout + createmanglechain tcpost + # + # Process the TC Rules File + # + strip_file tcrules + + while read mark sources dests proto ports sports user testval length; do + expandv mark sources dests proto ports sports user testval length + rule=$(echo "$mark $sources $dests $proto $ports $sports $user $testval $length") + process_tc_rule + done < $TMP_DIR/tcrules + # + # Link to the TC mangle chains from the main chains + # + + if [ -n "$ROUTEMARK_INTERFACES" ]; then + # + # Route marks are restored in PREROUTING/OUTPUT prior to these rules. We only send + # 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 + run_iptables -t mangle -A FORWARD -j tcfor + run_iptables -t mangle -A POSTROUTING -j tcpost + + if [ -n "$TC_SCRIPT" ]; then + + run_user_exit $TC_SCRIPT + + save_progress_message "Setting up Traffic Control..." + save_command . $TC_SCRIPT + elif [ -n "$TC_ENABLED" ]; then + setup_traffic_shaping + fi +} + +setup_tc() { + + progress_message2 "Setting up Traffic Control Rules..." + + setup_tc1 +} + +# +# Clear Traffic Shaping +# +delete_tc() +{ + clear_one_tc() { + save_command "tc qdisc del dev $1 root 2> /dev/null" + save_command "tc qdisc del dev $1 ingress 2> /dev/null" + + } + + save_progress_message "Clearing Traffic Control/QOS" + + run_user_exit tcclear + + cat >> $RESTOREBASE << __EOF__ +${INDENT}ip link list | while read inx interface details; do +${INDENT} case \$inx in +${INDENT} [0-9]*) +${INDENT} qt tc qdisc del dev \${interface%:} root +${INDENT} qt tc qdisc del dev \${interface%:} ingress +${INDENT} ;; +${INDENT} *) +${INDENT} ;; +${INDENT} esac +${INDENT}done +__EOF__ +} + +# +# Process a record from the accounting file +# +process_accounting_rule() { + rule= + rule2= + jumpchain= + user1= + + accounting_error() { + error_message "WARNING: Invalid Accounting rule" $action $chain $source $dest $proto $port $sport $user + } + + accounting_interface_error() { + error_message "WARNING: Unknown interface $1 in " $action $chain $source $dest $proto $port $sport $user + } + + accounting_interface_verify() { + verify_interface $1 || accounting_interface_error $1 + } + + jump_to_chain() { + if ! havechain $jumpchain; then + if ! createchain2 $jumpchain No; then + accounting_error + return 2 + fi + fi + + rule="$rule -j $jumpchain" + } + + do_ipp2p() { + [ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support" + case $proto in + *:*) + proto=${proto#*:} + ;; + *) + proto=tcp + ;; + esac + + rule="$rule -p $proto -m ipp2p --${port:-ipp2p}" + } + + case $source in + *:*) + accounting_interface_verify ${source%:*} + rule="$(source_ip_range ${source#*:}) $(match_source_dev ${source%:*})" + ;; + *.*.*.*|+*|!+*) + rule="$(source_ip_range $source)" + ;; + -|all|any) + ;; + *) + if [ -n "$source" ]; then + accounting_interface_verify $source + rule="$(match_source_dev $source)" + fi + ;; + esac + + [ -n "$dest" ] && case $dest in + *:*) + accounting_interface_verify ${dest%:*} + rule="$rule $(dest_ip_range ${dest#*:}) $(match_dest_dev ${dest%:*})" + ;; + *.*.*.*|+*|!*) + rule="$rule $(dest_ip_range $dest)" + ;; + -|all|any) + ;; + *) + accounting_interface_verify $dest + rule="$rule $(match_dest_dev $dest)" + ;; + esac + + [ -n "$proto" ] && case $proto in + -|any|all) + ;; + ipp2p|IPP2P|ipp2p:*|IPP2P:*) + do_ipp2p + ;; + *) + rule="$rule -p $proto" + ;; + esac + + multiport= + + [ -n "$port" ] && case $port in + -|any|all) + ;; + *) + if [ -n "$MULTIPORT" ]; then + rule="$rule -m multiport --dports $port" + multiport=Yes + else + rule="$rule --dport $port" + fi + ;; + esac + + [ -n "$sport" ] && case $sport in + -|any|all) + ;; + *) + if [ -n "$MULTIPORT" ]; then + [ -n "$multiport" ] && rule="$rule --sports $sport" || rule="$rule -m multiport --sports $sport" + else + rule="$rule --sport $sport" + fi + ;; + esac + + [ -n "$user" ] && case $user in + -|any|all) + ;; + *) + [ "$chain" != OUTPUT ] && \ + fatal_error "Invalid use of a user/group: chain is not OUTPUT but $chain" + rule="$rule -m owner" + user1="$user" + + case "$user" in + !*+*) + if [ -n "${user#*+}" ]; then + rule="$rule ! --cmd-owner ${user#*+} " + fi + user1=${user%+*} + ;; + *+*) + if [ -n "${user#*+}" ]; then + rule="$rule --cmd-owner ${user#*+} " + fi + user1=${user%+*} + ;; + esac + + case "$user1" in + !*:*) + if [ "$user1" != "!:" ]; then + temp="${user1#!}" + temp="${temp%:*}" + [ -n "$temp" ] && rule="$rule ! --uid-owner $temp " + temp="${user1#*:}" + [ -n "$temp" ] && rule="$rule ! --gid-owner $temp " + fi + ;; + *:*) + if [ "$user1" != ":" ]; then + temp="${user1%:*}" + [ -n "$temp" ] && rule="$rule --uid-owner $temp " + temp="${user1#*:}" + [ -n "$temp" ] && rule="$rule --gid-owner $temp " + fi + ;; + !*) + [ "$user1" != "!" ] && rule="$rule ! --uid-owner ${user1#!} " + ;; + *) + [ -n "$user1" ] && rule="$rule --uid-owner $user1 " + ;; + esac + ;; + esac + + case $action in + COUNT) + ;; + DONE) + rule="$rule -j RETURN" + ;; + *:COUNT) + rule2="$rule" + jumpchain=${action%:*} + jump_to_chain || return + ;; + JUMP:*) + jumpchain=${action#*:} + jump_to_chain || return + ;; + *) + jumpchain=$action + jump_to_chain || return + ;; + esac + + [ "x${chain:=accounting}" = "x-" ] && chain=accounting + + ensurechain1 $chain + + if do_iptables -A $chain $(fix_bang $rule) ; then + [ -n "$rule2" ] && run_iptables2 -A $jumpchain $rule2 + progress_message " Accounting rule" $action $chain $source $dest $proto $port $sport $user $DONE + save_progress_message_short " Accounting rule $action $chain $source $dest $proto $port $sport $user Added" + else + accounting_error + fi +} + +# +# Set up Accounting +# +setup_accounting() # $1 = Name of accounting file +{ + + progress_message2 "Setting up Accounting..." + + save_progress_message "Setting up Accounting..." + + strip_file accounting $1 + + while read action chain source dest proto port sport user ; do + expandv action chain source dest proto port sport user + process_accounting_rule + done < $TMP_DIR/accounting + + if havechain accounting; then + for chain in INPUT FORWARD OUTPUT; do + run_iptables -I $chain -j accounting + done + fi + +} + +# +# Add one Filter Rule from an action -- Helper function for the action file processor +# +# The caller has established the following variables: +# COMMAND = current command. +# 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 +# +add_an_action() +{ + local chain1 + + do_ports() { + if [ -n "$port" ]; then + dports="--dport" + if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then + multiport="$multioption" + dports="--dports" + fi + dports="$dports $port" + fi + + if [ -n "$cport" ]; then + sports="--sport" + if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then + multiport="$multioption" + sports="--sports" + fi + sports="$sports $cport" + fi + } + + interface_error() + { + fatal_error "Unknown interface $1 in rule: \"$rule\"" + } + + action_interface_verify() + { + verify_interface $1 || interface_error $1 + } + + 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= + } + + do_ipp2p() { + [ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\"" + + dports="-m ipp2p --${port:-ipp2p}" + + case $proto in + ipp2p|IPP2P) + proto=tcp + port= + do_ports + ;; + ipp2p:udpIPP2P:UDP) + proto=udp + port= + do_ports + ;; + ipp2p:all|IPP2P:ALL) + proto=all + ;; + esac + } + + # Set source variables. The 'cli' variable will hold the client match predicate(s). + + cli= + + case "$client" in + -) + ;; + *:*) + action_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 + action_interface_verify $client + cli="$(match_source_dev $client)" + fi + ;; + esac + + # Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s). + + dest_interface= + serv= + + case "$server" in + -) + ;; + *.*.*|+*|!+*) + serv=$server + ;; + ~*) + fatal_error "Rule \"$rule\" - Destination may not be specified by MAC Address" + ;; + *) + if [ -n "$server" ]; then + action_interface_verify $server + dest_interface="$(match_dest_dev $server)" + fi + ;; + esac + + # Setup protocol and port variables + + sports= + dports= + proto=$protocol + servport=$serverport + multiport= + chain1=$chain + user="$userandgroup" + + [ 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" + ;; + ipp2p|IPP2P|ipp2p:*|IPP2P:*) + do_ipp2p + ;; + *) + [ -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 + + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi + + if [ -n "${serv}" ]; then + for serv1 in $(separate_list $serv); do + for srv in $(firewall_ip_range $serv1); do + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ + $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) + fi + + run_iptables2 -A $chain1 $proto $multiport $cli $sports \ + $(dest_ip_range $srv) $dports $ratelimit $user -j $target + done + done + else + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ + $(fix_bang $proto $sports $multiport $cli $dest_interface $dports) + fi + + run_iptables2 -A $chain1 $proto $multiport $cli $dest_interface $sports \ + $dports $ratelimit $user -j $target + fi +} + +# +# Process a record from an action file +# +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 +{ + 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}" + local userandgroup= + local logtag= + + if [ -n "$ratelimit" ]; then + case $ratelimit in + -) + ratelimit= + ;; + *:*) + ratelimit="-m limit --limit ${ratelimit%:*} --limit-burst ${ratelimit#*:}" + ;; + *) + ratelimit="-m limit --limit $ratelimit" + ;; + esac + fi + + [ "x$userspec" = "x-" ] && userspec= + + if [ -n "$userspec" ]; then + userandgroup="-m owner" + + case "$userspec" in + !*+*) + if [ -n "${userspec#*+}" ]; then + userandgroup="$userandgroup ! --cmd-owner ${userspec#*+}" + fi + userspec=${userspec%+*} + ;; + *+*) + if [ -n "${userspec#*+}" ]; then + userandgroup="$userandgroup --cmd-owner ${userspec#*+}" + fi + userspec=${userspec%+*} + ;; + esac + + case "$userspec" in + !*:*) + if [ "$userspec" != "!:" ]; then + temp="${userspec#!}" + temp="${temp%:*}" + [ -n "$temp" ] && userandgroup="$userandgroup ! --uid-owner $temp" + temp="${userspec#*:}" + [ -n "$temp" ] && userandgroup="$userandgroup ! --gid-owner $temp" + fi + ;; + *:*) + if [ "$userspec" != ":" ]; then + temp="${userspec%:*}" + [ -n "$temp" ] && userandgroup="$userandgroup --uid-owner $temp" + temp="${userspec#*:}" + [ -n "$temp" ] && userandgroup="$userandgroup --gid-owner $temp" + fi + ;; + !*) + [ "$userspec" != "!" ] && userandgroup="$userandgroup ! --uid-owner ${userspec#!}" + ;; + *) + [ -n "$userspec" ] && userandgroup="$userandgroup --uid-owner $userspec" + ;; + esac + + [ "$userandgroup" = "-m owner" ] && userandgroup= + fi + + # Isolate log level + + if [ "$target" = "${target%:*}" ]; then + loglevel= + else + loglevel="${target#*:}" + target="${target%%:*}" + expandv loglevel + if [ "$loglevel" != "${loglevel%:*}" ]; then + logtag="${loglevel#*:}" + loglevel="${loglevel%:*}" + expandv logtag + fi + + case $loglevel in + none*) + loglevel= + [ $target = LOG ] && return + ;; + esac + + loglevel=${loglevel%\!} + fi + + logtarget="$target" + + case $target in + REJECT) + target=reject + ;; + CONTINUE) + target=RETURN + ;; + *) + ;; + esac + + 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 + + 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 + + # Generate Netfilter rule(s) + + [ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all} + + 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_an_action() modifies these so we must set their values each time + # + port=${ports:=-} + cport=${cports:=-} + add_an_action + done + done + elif [ -n "$MULTIPORT" ] && \ + ! list_search $protocol "icmp" "ICMP" "1" && \ + [ "$ports" = "${ports%:*}" -a \ + "$cports" = "${cports%:*}" -a \ + $(list_count $ports) -le 15 -a \ + $(list_count $cports) -le 15 ] + 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" + for client in $(separate_list $clients); do + for server in $(separate_list $servers); do + # + # add_an_action() modifies these so we must set their values each time + # + port=${ports:=-} + cport=${cports:=-} + add_an_action + done + done + else + # + # MULTIPORT is disabled or the rule isn't compatible with multiport match + # + multioption= + 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 + add_an_action + done + done + done + done + fi + # + # Report Result + # + progress_message " Rule \"$rule\" $DONE." + save_progress_message_short " Rule \"$rule\" added." +} + +# +# Create and record a log action chain -- Log action chains have names +# that are formed from the action name by prepending a "%" and appending +# a 1- or 2-digit sequence number. In the functions that follow, +# 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 , we maintain two variables: +# +# _actchain - The action chain number. +# _chains - List of ( level[:tag] , chainname ) pairs +# +# 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 +# it adds the leading "%" and trailing sequence number. + +createlogactionchain() # $1 = Action Name, $2 = Log Level [: Log Tag ] +{ + local actchain= action=$1 level=$2 + + eval actchain=\${${action}_actchain} + + case ${#action} in + 29|30) + CHAIN=$(echo $action | truncate 28) # %...n makes 30 + ;; + *) + CHAIN=${action} + ;; + esac + + while havechain %${CHAIN}${actchain}; do + actchain=$(($actchain + 1)) + [ $actchain -eq 10 -a ${#CHAIN} -eq 28 ] && CHAIN=$(echo $CHAIN | truncate 27) # %...nn makes 30 + done + + CHAIN=%${CHAIN}${actchain} + + eval ${action}_actchain=$(($actchain + 1)) + + createchain $CHAIN No + LEVEL=${level%:*} + if [ "$LEVEL" != "$level" ]; then + TAG=${level#*:} + else + TAG= + fi + + [ none = "${LEVEL%\!}" ] && LEVEL= + + run_user_exit $1 + + eval ${action}_chains=\"\$${action}_chains $level $CHAIN\" + +} + +# +# Create an action chain and run it's associated user exit +# + +createactionchain() # $1 = Action, including log level and tag if any +{ + case $1 in + *::*) + fatal_error "Invalid ACTION $1" + ;; + *:*:*) + set -- $(split $1) + createlogactionchain $1 $2:$3 + ;; + *:*) + set -- $(split $1) + createlogactionchain $1 $2 + ;; + *) + CHAIN=$1 + LEVEL= + TAG= + createchain $CHAIN no + run_user_exit $CHAIN + ;; + 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#*:} + ;; + *) + havechain $action || fatal_error "Fatal error in find_logactionchain" + echo $action + return + ;; + esac + + eval chains="\$${action}_chains" + + set -- $chains + + while [ $# -gt 0 ]; do + [ "$1" = "$level" ] && { echo $2 ; return ; } + shift 2 + done + + fatal_error "Fatal error in find_logactionchain" + +} + +# +# This function determines the logging for a subordinate action or a rule within a subordinate action +# +merge_levels() # $1=level at which superior action is called, $2=level at which the subordinate rule is called +{ + local superior=$1 subordinate=$2 + + set -- $(split $1) + + case $superior in + *:*:*) + case $2 in + 'none!') + echo ${subordinate%%:*}:'none!':$3 + return + ;; + *'!') + echo ${subordinate%%:*}:$2:$3 + return + ;; + *) + case $subordinate in + *:*:*) + echo $subordinate + return + ;; + *:*) + echo $subordinate:$3 + return + ;; + *) + 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 +} + +# This function substitutes the second argument for the first part of the first argument up to the first colon (":") +# +# Example: +# +# substitute_action DNAT PARAM:info:FTP +# +# produces "DNAT:info:FTP" +# +substitute_action() # $1 = parameter, $2 = action +{ + local logpart=${2#*:} + + 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 + + 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 + + if [ -f $(find_file macro.$macro) ]; then + echo $macro/$aktion + return + fi + fi + + echo $1 +} + +# +# Combine a source/dest from the macro body with one from the macro invocation +# +merge_macro_source_dest() # $1 = source/dest from macro body, $2 = source/dest from invocation +{ + case $2 in + -) + echo ${1} + ;; + *.*.*|+*|~*) + # + # Value in the invocation is an address -- put it behind the value from the macro + # + echo ${1}:${2} + ;; + *) + echo ${2}:${1} + ;; + esac +} + +# +# 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. +# c) A dependency graph is created. For each , the variable 'requiredby_' lists the +# action[:level[:tag]] of each action invoked by . +# d) All actions are listed in the global variable ACTIONS. +# e) Common actions are recorded (in variables of the name _common) and are added to the global +# USEDACTIONS +# +# As the rules file is scanned, each action[:level[:tag]] is merged onto the USEDACTIONS list. When an +# is merged onto this list, its action chain is created. Where logging is specified, a chain with the name +# %n is used where the name is truncated on the right where necessary to ensure that the total +# length of the chain name does not exceed 30 characters. +# +# The second phase (process_actions2) occurs after the rules file is scanned. The transitive closure of +# 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() { + + ACTIONS="dropBcast allowBcast dropNotSyn rejNotSyn dropInvalid allowInvalid allowinUPnP allowoutUPnP forwardUPnP" + + 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 + + [ "$xaction" = "$(chain_base $xaction)" ] || startup_error "Invalid Action Name: $xaction" + + if ! list_search $xaction $ACTIONS; then + f=action.$xaction + fn=$(find_file $f) + + eval requiredby_${action}= + + if [ -f $fn ]; then + progress_message2 " Pre-processing $fn..." + strip_file $f $fn + while read xtarget xclients xservers xprotocol xports xcports xratelimit $xuserspec; do + expandv xtarget + temp="${xtarget%%:*}" + case "$temp" in + ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE) + ;; + *) + if list_search $temp $ACTIONS; then + eval requiredby=\"\$requiredby_${xaction}\" + list_search $xtarget $requiredby || eval requiredby_${xaction}=\"$requiredby $xtarget\" + else + 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) + + if [ ! -f $TMP_DIR/$f1 ]; then + # + # We must only verify macros once to ensure that they don't invoke any non-standard actions + # + if [ -f $fn ]; then + strip_file $f1 $fn + + progress_message " ..Expanding Macro $fn..." + + 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\"" + esac + done < $TMP_DIR/$f1 + + progress_message " ..End Macro" + else + rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec" + startup_error "Invalid TARGET in rule \"$rule\"" + fi + fi + fi + ;; + + esac + done < $TMP_DIR/$f + else + startup_error "Missing Action File: $f" + fi + + ACTIONS="$ACTIONS $xaction" + fi + done < $TMP_DIR/$inputfile + done +} + +process_actions2() { + + local interfaces="$(find_interfaces_by_option upnp)" + + if [ -n "$interfaces" ]; then + if ! list_search forwardUPnP $USEDACTIONS; then + error_message "WARNING:Missing forwardUPnP rule (required by 'upnp' interface option on $interfaces)" + USEDACTIONS="$USEDACTIONS forwardUPnP" + fi + fi + + progress_message " Generating Transitive Closure of Used-action List..." + + changed=Yes + + while [ -n "$changed" ]; do + changed= + for xaction in $USEDACTIONS; do + + eval required=\"\$requiredby_${xaction%%:*}\" + + 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 + changed=Yes + fi + done + done + done +} + +process_actions3() { + + for xaction in $USEDACTIONS; do + # + # 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 + + save_progress_message "Creating action chain $xaction1" + + # + # Handle Builtin actions + # + case $xaction1 in + dropBcast) + if [ -n "$USEPKTTYPE" ]; then + 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 + + run_iptables -A dropBcast -m pkttype --pkt-type broadcast -j DROP + run_iptables -A dropBcast -m pkttype --pkt-type multicast -j DROP + else + for interface in $(find_bcastdetect_interfaces); do + cat >> $RESTOREBASE << __EOF__ + +${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do +__EOF__ + case $xlevel in + none*) + ;; + *) + [ -n "$xlevel" ] && \ + cat >> $RESTOREBASE << __EOF__ +${INDENT} log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -d \$address +__EOF__ + ;; + esac + + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -A $xchain -d \$address -j DROP +${INDENT}done + +__EOF__ + done + + 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 + + run_iptables -A $xchain -d $address -j DROP + done + fi + ;; + allowBcast) + if [ -n "$USEPKTTYPE" ]; then + 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 + + run_iptables -A allowBcast -m pkttype --pkt-type broadcast -j ACCEPT + run_iptables -A allowBcast -m pkttype --pkt-type multicast -j ACCEPT + else + for interface in $(find_bcastdetect_interfaces); do + cat >> $RESTOREBASE << __EOF__ + +${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do +__EOF__ + case $xlevel in + none*) + ;; + *) + [ -n "$xlevel" ] && \ + cat >> $RESTOREBASE << __EOF__ +${INDENT} log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -d \$address +__EOF__ + ;; + esac + + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -A $xchain -d \$address -j +${INDENT}done + +__EOF__ + done + + 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 + + run_iptables -A $xchain -d $address -j ACCEPT + done + fi + ;; + dropNotSyn) + 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 + ;; + rejNotSyn) + [ -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 + ;; + dropInvalid) + [ -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 + ;; + allowInvalid) + [ -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 + ;; + forwardUPnP) + ;; + allowinUPnP) + 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 + ;; + allowoutUPnP) + [ -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 + ;; + *) + # + # Not a builtin + # + f=action.$xaction1 + + progress_message2 "$DOING $(find_file $f) for Chain $xchain..." + + 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) + + is_macro= + param= + + xtarget1=${xaction2%%:*} + + case $xtarget1 in + ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE) + # + # Builtin target -- Nothing to do + # + ;; + *) + 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 + ;; + esac + + expandv xclients xservers xprotocol xports xcports xratelimit xuserspec + + if [ -n "$is_macro" ]; then + + xtarget1=$(map_old_action $xtarget1) + + 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 + + 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 + + if [ -n "$mclients" ]; then + case $mclients in + -) + mclients=${xclients} + ;; + *) + mclients=$(merge_macro_source_dest $mclients $xclients) + ;; + esac + else + mclients=${xclients} + fi + + if [ -n "$mservers" ]; then + case $mservers in + -) + mservers=${xservers} + ;; + *) + mservers=$(merge_macro_source_dest $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 + done < $TMP_DIR/$f + ;; + esac + done +} + +# +# Add a NAT rule - Helper function for the rules file processor +# +# The caller has established the following variables: +# COMMAND = The current command +# the motions. +# 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 +# ratelimit = Optional rate limiting clause +# userandgroup = -m owner match to limit the rule to a particular user and/or group +# logtag = Log tag +# excludesource = Source Exclusion List +# +add_nat_rule() { + local chain + local excludedests= + + # Be sure we can NAT + + if [ -z "$NAT_ENABLED" ]; then + fatal_error "Rule \"$rule\" requires NAT which is disabled" + fi + + # Parse SNAT address if any + + if [ "$addr" != "${addr%:*}" ]; then + fatal_error "SNAT may no longer be specified in a DNAT rule; use /etc/shorewall/masq instead" + fi + + # Set original destination address + + case $addr in + all) + addr= + ;; + detect) + eval interfaces=\$${source}_interfaces + + if [ -n "$DETECT_DNAT_IPADDRS" -a "$source" != "$FW" ]; then + + save_command "" + if [ $(list_count1 $interfaces) -eq 1 ]; then + save_command "addr=\$(find_first_interface_address $interface)" + else + savecomment "addr=" + for interface in $interfaces; do + cat >> $RESTOREBASE << __EOF__ +${INDENT}addr="\$addr \$(find_first_interface_address $interface)" +__EOF__ + done + fi + fi + ;; + !*) + if [ $(list_count $addr) -gt 1 ]; then + excludedests="${addr#\!}" + addr= + fi + ;; + esac + + addr=${addr:-0.0.0.0/0} + + # Select target + + 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 + servport="${servport:+:$servport}" + serv1= + for srv in $(separate_list $serv); do + serv1="$serv1 --to-destination ${srv}${servport}" + done + target1="DNAT $serv1" + else + target1="REDIRECT --to-port $servport" + fi + + if [ $source = $FW ]; then + [ -n "$excludezones" ] && fatal_error "Invalid Source in rule \"$rule\"" + fi + + # Generate nat table rules + + if [ "$source" = "$FW" ]; then + if [ -n "${excludesource}${excludedests}" ]; then + build_exclusion_chain chain nat "$excludesource" $excludedests + + for adr in $(separate_list $addr); do + run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain + done + + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat + fi + + addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection + else + for adr in $(separate_list $addr); do + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel OUTPUT OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat \ + $(fix_bang $proto $cli $sports $userandgroup $(dest_ip_range $adr) $multiport $dports) + fi + + run_iptables2 -t nat -A OUTPUT $ratelimit $proto $sports $userandgroup $(dest_ip_range $adr) $multiport $dports -j $target1 + done + fi + else + if [ -n "${excludesource}${excludedests}${excludezones}" ]; then + build_exclusion_chain chain nat "$excludesource" $excludedests + + if [ $addr = detect ]; then + ensurenatchain $(dnat_chain $source) + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}for adr in \$addr; do +${INDENT} run_iptables -t nat -A $(fix_bang $(dnat_chain $source) $cli $proto $multiport $sports $dports) -d \$adr -j $chain +__EOF__ + else + for adr in $(separate_list $addr); do + addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain + done + fi + + 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 + + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $(dnat_chain $source) $logtarget "$ratelimit" "$logtag" -A -t nat + fi + + addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection + else + chain=$(dnat_chain $source) + + if [ $addr = detect ]; then + ensurenatchain $chain + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}for adr in \$addr; do +__EOF__ + if [ -n "$loglevel" ]; then + cat >> $RESTOREBASE << __EOF__ +${INDENT} log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat $(fix_bang $proto $cli $sports $multiport $dports) -d \$adr +__EOF__ + fi + + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -t nat -A $chain $(fix_bang $proto $ratelimit $cli $sports $multiport $dports) -d \$adr -j $target1 +__EOF__ + else + for adr in $(separate_list $addr); do + if [ -n "$loglevel" ]; then + ensurenatchain $chain + log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat \ + $(fix_bang $proto $cli $sports $(dest_ip_range $adr) $multiport $dports) + fi + + addnatrule $chain $proto $ratelimit $cli $sports \ + -d $adr $multiport $dports -j $target1 + done + fi + fi + fi + + # Replace destination port by the new destination port + + if [ -n "$servport" ]; then + if [ -z "$multiport" ]; then + dports="--dport ${servport#*:}" + else + dports="--dports ${servport#*:}" + fi + fi + + [ "x$addr" = "x0.0.0.0/0" ] && addr= + ratelimit= +} + +# +# Process a record from the rules file +# +process_rule() # $1 = target + # $2 = clients + # $3 = servers + # $4 = protocol + # $5 = ports + # $6 = cports + # $7 = address + # $8 = ratelimit + # $9 = userspec +{ + 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. + # 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 + # chain = The canonical chain for this rule + # 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 + # + add_a_rule() + { + local natrule= + + do_ports() { + if [ -n "$port" ]; then + dports="--dport" + if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then + multiport="$multioption" + dports="--dports" + fi + dports="$dports $port" + fi + + if [ -n "$cport" ]; then + sports="--sport" + if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then + multiport="$multioption" + sports="--sports" + fi + sports="$sports $cport" + fi + } + + interface_error() + { + fatal_error "Unknown interface $1 in rule: \"$rule\"" + } + + rule_interface_verify() + { + verify_interface $1 || interface_error $1 + } + + handle_exclusion() + { + build_exclusion_chain chain filter "$excludesource" "$excludedest" + + if [ -n "$addr" -a -n "$CONNTRACK_MATCH" ]; then + for adr in $(separate_list $addr); do + run_iptables -A $logchain $state $(fix_bang $proto $sports $multiport $dports) $user -m conntrack --ctorigdst $adr -j $chain + done + addr= + else + run_iptables -A $state $logchain $(fix_bang $cli $proto $sports $multiport $dports) $user -j $chain + fi + + cli= + proto= + sports= + multiport= + dports= + user= + state= + } + + do_ipp2p() { + [ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\"" + + dports="-m ipp2p --${port:-ipp2p}" + + case $proto in + ipp2p|IPP2P|ipp2p:tcp|IPP2P:TCP) + port= + proto=tcp + do_ports + ;; + ipp2p:udp|IPP2P:UDP) + port= + proto=udp + do_ports + ;; + ipp2p:all|IPP2P:ALL) + port= + proto=all + ;; + *) + fatal_error "Invalid IPP2P protocol ${proto#*:}. Rule: \"$rule\"" + ;; + esac + } + + # Set source variables. The 'cli' variable will hold the client match predicate(s). + + cli= + + 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 + + # Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s). + + dest_interface= + serv= + + 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 + + # Setup protocol and port variables + + sports= + dports= + proto=$protocol + addr=$address + servport=$serverport + multiport= + user="$userandgroup" + + # Restore $chain to the canonical chain. + + chain=$logchain + + [ 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" + ;; + all|ALL) + [ -n "$port" ] && \ + fatal_error "Port number not allowed with protocol \"all\"; rule: \"$rule\"" + proto= + ;; + ipp2p|IPP2P|ipp2p:*|IPP2P:*) + do_ipp2p + ;; + *) + [ -n "$port" ] && \ + fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\"" + ;; + esac + + proto="${proto:+-p $proto}" + + # Some misc. setup + + case "$logtarget" in + ACCEPT|DROP|REJECT|CONTINUE) + if [ -z "$proto" -a -z "$cli" -a -z "$serv" -a -z "$servport" -a -z "$user" -a -z "$excludesource" -a -z "$excludedest" ] ; then + 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\"" + + [ -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\"" + + [ -n "$serv" ] || \ + fatal_error "$logtarget rules require a server address; rule: \"$rule\"" + natrule=Yes + ;; + LOG) + [ -z "$loglevel" ] && \ + fatal_error "LOG requires log level" + ;; + esac + + case $SECTION in + ESTABLISHED|RELATED) + state="-m state --state $SECTION" + ;; + *) + state= + ;; + esac + + if [ -n "${serv}${servport}" ]; then + + # A specific server or server port given + + 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 + + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi + + 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 + if [ "$addr" = detect ]; then + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -A $chain $state $proto $ratelimit $multiport $cli $sports $(dest_ip_range $srv) $dports -m conntrack --ctorigdst \$adr $user -j $target +${INDENT}done + +__EOF__ + else + 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 \ + $user $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) $state + fi + + run_iptables2 -A $chain $state $proto $ratelimit $multiport $cli $sports \ + $(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $user -j $target + done + fi + else + if [ -n "$loglevel" -a -z "$natrule" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) + fi + + if [ -n "$nonat" ]; then + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $(dest_ip_range $srv) $dports $ratelimit $user -j RETURN + fi + + if [ "$logtarget" != NONAT ]; then + run_iptables2 -A $chain $state $proto $multiport $cli $sports \ + $(dest_ip_range $srv) $dports $ratelimit $user -j $target + fi + fi + done + done + else + if [ -n "$loglevel" -a -z "$natrule" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $sports $multiport $cli $dports) + fi + + [ -n "$nonat" ] && \ + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $dports $ratelimit $user -j RETURN + + [ "$logtarget" != NONAT ] && \ + run_iptables2 -A $chain $state $proto $multiport $cli $sports \ + $dports $ratelimit $user -j $target + fi + fi + else + + # Destination is a simple zone + + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi + + if [ -n "$addr" ]; then + for adr in $(separate_list $addr); do + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr) + fi + + if [ "$logtarget" != LOG ]; then + if [ -n "$nonat" ]; then + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j RETURN + fi + + if [ "$logtarget" != NONAT ]; then + run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \ + $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j $target + fi + fi + done + else + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports) + fi + + if [ "$logtarget" != LOG ]; then + if [ -n "$nonat" ]; then + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $dports $ratelimit $user -j RETURN + fi + + if [ "$logtarget" != NONAT ]; then + run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \ + $sports $dports $ratelimit $user -j $target + fi + fi + fi + fi + } + + # # # # # F u n c t i o n B o d y # # # # # + + [ "x$ratelimit" = "x-" ] && ratelimit= + + if [ -n "$ratelimit" ]; then + case $ratelimit in + *:*) + ratelimit="-m limit --limit ${ratelimit%:*} --limit-burst ${ratelimit#*:}" + ;; + *) + ratelimit="-m limit --limit $ratelimit" + ;; + esac + fi + + # Isolate log level + + if [ "$target" = "${target%:*}" ]; then + loglevel= + else + loglevel="${target#*:}" + target="${target%%:*}" + expandv loglevel + if [ "$loglevel" != "${loglevel%:*}" ]; then + logtag="${loglevel#*:}" + loglevel="${loglevel%:*}" + expandv logtag + fi + + case $loglevel in + none*) + loglevel= + [ $target = LOG ] && return + ;; + esac + + loglevel=${loglevel%\!} + fi + # + # 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 + + # Tranform the rule: + # + # - parse the user specification + # - 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 '-' + + [ "x$userspec" = x- ] && userspec= + [ "x$address" = "x-" ] && address= + + if [ -n "$userspec" ]; then + + userandgroup="-m owner" + + case "$userspec" in + !*+*) + if [ -n "${userspec#*+}" ]; then + userandgroup="$userandgroup ! --cmd-owner ${userspec#*+}" + fi + userspec=${userspec%+*} + ;; + *+*) + if [ -n "${userspec#*+}" ]; then + userandgroup="$userandgroup --cmd-owner ${userspec#*+}" + fi + userspec=${userspec%+*} + ;; + esac + + case "$userspec" in + !*:*) + if [ "$userspec" != "!:" ]; then + temp="${userspec#!}" + temp="${temp%:*}" + [ -n "$temp" ] && userandgroup="$userandgroup ! --uid-owner $temp" + temp="${userspec#*:}" + [ -n "$temp" ] && userandgroup="$userandgroup ! --gid-owner $temp" + fi + ;; + *:*) + if [ "$userspec" != ":" ]; then + temp="${userspec%:*}" + [ -n "$temp" ] && userandgroup="$userandgroup --uid-owner $temp" + temp="${userspec#*:}" + [ -n "$temp" ] && userandgroup="$userandgroup --gid-owner $temp" + fi + ;; + !*) + [ "$userspec" != "!" ] && userandgroup="$userandgroup ! --uid-owner ${userspec#!}" + ;; + *) + [ -n "$userspec" ] && userandgroup="$userandgroup --uid-owner $userspec" + ;; + esac + + [ "$userandgroup" = "-m owner" ] && userandgroup= + fi + + case $target in + ACCEPT+|NONAT) + [ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION" + nonat=Yes + target=ACCEPT + ;; + ACCEPT|LOG) + ;; + DROP) + [ -n "$ratelimit" ] && fatal_error "Rate Limiting not available with DROP" + ;; + REJECT) + target=reject + ;; + CONTINUE) + target=RETURN + ;; + DNAT*|SAME*) + [ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION" + target=ACCEPT + address=${address:=detect} + ;; + REDIRECT*) + [ $SECTION = NEW ] || fatal_error "REDIRECT rules are not allowed in the $SECTION SECTION" + target=ACCEPT + address=${address:=all} + if [ "x-" = "x$servers" ]; then + servers=$FW + else + servers="$FW::$servers" + fi + ;; + *-) + [ $SECTION = NEW ] || fatal_error "$target rules are not allowed in the $SECTION SECTION" + ;; + esac + + # Parse and validate source + + if [ "$clients" = "${clients%:*}" ]; then + clientzone="$clients" + clients= + else + clientzone="${clients%%:*}" + clients="${clients#*:}" + [ -z "$clientzone" -o -z "$clients" ] && \ + fatal_error "Empty source zone or qualifier: rule \"$rule\"" + fi + + 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 + + if [ "$clientzone" = "${clientzone%!*}" ]; then + excludezones= + else + excludezones="${clientzone#*!}" + clientzone="${clientzone%!*}" + + case $logtarget in + DNAT|REDIRECT|SAME) + ;; + *) + fatal_error "Exclude zone only allowed with DNAT, SAME or REDIRECT" + ;; + esac + fi + + validate_zone $clientzone || fatal_error "Undefined Client Zone in rule \"$rule\"" + + # Parse and validate destination + + source=$clientzone + + if [ $source = $FW ]; then + source_hosts= + elif [ -n "$userspec" ]; then + fatal_error "Invalid use of a user-qualification: rule \"$rule\"" + else + eval source_hosts=\"\$${source}_hosts\" + fi + + if [ "$servers" = "${servers%:*}" ] ; then + serverzone="$servers" + servers= + serverport= + else + serverzone="${servers%%:*}" + servers="${servers#*:}" + if [ "$servers" != "${servers%:*}" ] ; then + serverport="${servers#*:}" + servers="${servers%:*}" + [ -z "$serverzone" -o -z "$serverport" ] && \ + fatal_error "Empty destination zone or server port: rule \"$rule\"" + if [ $(list_count $servers) -gt 1 ]; then + case $servers in + !*) + fatal_error "Exclude lists not supported in the DEST column" + ;; + esac + fi + else + serverport= + [ -z "$serverzone" -o -z "$servers" ] && \ + fatal_error "Empty destination zone or qualifier: rule \"$rule\"" + fi + fi + + 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 + + if ! validate_zone $serverzone; then + fatal_error "Undefined Server Zone in rule \"$rule\"" + fi + + dest=$serverzone + + # Ensure that this rule doesn't apply to a NONE policy pair of zones + + chain=${source}2${dest} + + # If we have one or more exclusion lists, we will create a new chain and + # store it's name in 'chain'. We still want log rules to reflect the + # canonical chain so we store it's name in $logchain. + + logchain=$chain + + eval policy=\$${chain}_policy + + [ -z "$policy" ] && \ + fatal_error "No policy defined from zone $source to zone $dest" + + [ $policy = NONE ] && \ + fatal_error "Rules may not override a NONE policy: rule \"$rule\"" + + [ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all} + + ensurechain $chain + + # Generate Netfilter rule(s) + + case $logtarget in + DNAT*|SAME) + + 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:=-} + add_a_rule + done + elif [ -n "$MULTIPORT" ] && \ + ! list_search $protocol "icmp" "ICMP" "1" && \ + [ "$ports" = "${ports%:*}" -a \ + "$cports" = "${cports%:*}" -a \ + $(list_count $ports) -le 15 -a \ + $(list_count $cports) -le 15 ] + 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" + 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:=-} + add_a_rule + done + else + # + # MULTIPORT is disabled or the rule isn't compatible with multiport match + # + multioption= + for client in $(separate_list ${clients:=-}); do + for port in $(separate_list ${ports:=-}); do + for cport in $(separate_list ${cports:=-}); do + server=${servers:=-} + add_a_rule + done + done + done + fi + ;; + *) + + 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:=-} + add_a_rule + done + done + elif [ -n "$MULTIPORT" ] && \ + ! list_search $protocol "icmp" "ICMP" "1" && \ + [ "$ports" = "${ports%:*}" -a \ + "$cports" = "${cports%:*}" -a \ + $(list_count $ports) -le 15 -a \ + $(list_count $cports) -le 15 ] + 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" + 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:=-} + add_a_rule + done + done + else + # + # MULTIPORT is disabled or the rule isn't compatible with multiport match + # + multioption= + 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 + add_a_rule + done + done + done + done + fi + ;; + esac + # + # Report Result + # + progress_message " Rule \"$rule\" $DONE." + save_progress_message_short " Rule \"$rule\" added." +} + +# +# 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 + + 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" + ;; + esac + + case ${mtarget%%:*} in + 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 + + mtarget=$(find_logactionchain $mtarget) + else + fatal_error "Invalid Action in rule \"$mtarget ${mclients:--} ${mservers:--} ${mprotocol:--} ${mports:--} ${mcports:--} ${xaddress:--} ${mratelimit:--} ${muserspec:--}\"" + fi + ;; + esac + + if [ -n "$mclients" ]; then + case $mclients in + -) + mclients=${iclients} + ;; + *) + mclients=$(merge_macro_source_dest $mclients $iclients) + ;; + esac + else + mclients=${iclients} + fi + + if [ -n "$mservers" ]; then + case $mservers in + -) + mservers=${iservers} + ;; + *) + mservers=$(merge_macro_source_dest $mservers $iservers) + ;; + esac + else + mservers=${iservers} + fi + + [ -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 + + 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%%:*} + + progress_message "..End Macro" + +} + +# +# Process the rules file +# +process_rules() +{ + # + # Process a rule where the source or destination is "all" + # + process_wildcard_rule() # $1 = Yes, if this is a macro, $2 = Yes if we want intrazone traffic + { + local yclients yservers ysourcezone ydestzone ypolicy + + for yclients in $xclients; do + for yservers in $xservers; do + ysourcezone=${yclients%%:*} + ydestzone=${yservers%%:*} + if [ "${ysourcezone}" != "${ydestzone}" -o "$2" = Yes ] ; then + eval ypolicy=\$${ysourcezone}2${ydestzone}_policy + if [ "$ypolicy" != NONE ] ; then + 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 + fi + fi + done + done + } + + do_it() # $1 = "Yes" if the target is a macro. + { + expandv xprotocol xports xcports xaddress xratelimit xuserspec intrazone= + + if [ -z "$SECTIONS" ]; then + finish_section ESTABLISHED,RELATED + SECTIONS="ESTABLISHED RELATED NEW" + SECTION=NEW + fi + + case $xclients in + all+) + xclients=all + intrazone=Yes + ;; + esac + + case $xservers in + all+) + xservers=all + intrazone=Yes + ;; + esac + + if [ "x$xclients" = xall ]; then + xclients="$ZONES $FW" + if [ "x$xservers" = xall ]; then + xservers="$ZONES $FW" + fi + process_wildcard_rule "$1" $intrazone + return + fi + + if [ "x$xservers" = xall ]; then + xservers="$ZONES $FW" + process_wildcard_rule "$1" $intrazone + return + fi + + 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 + } + + while read xtarget xclients xservers xprotocol xports xcports xaddress xratelimit xuserspec; do + expandv xtarget xclients xservers + + if [ "x$xclients" = xnone -o "x$servers" = xnone ]; then + rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec" + progress_message " Rule \"$rule\" ignored." + continue + fi + + case "${xtarget%%:*}" in + ACCEPT|ACCEPT+|NONAT|DROP|REJECT|DNAT|DNAT-|REDIRECT|REDIRECT-|LOG|CONTINUE|QUEUE|SAME|SAME-) + do_it No + ;; + 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 + ;; + *) + if list_search ${xtarget%%:*} $ACTIONS; then + if ! list_search $xtarget $USEDACTIONS; then + createactionchain $xtarget + USEDACTIONS="$USEDACTIONS $xtarget" + fi + + xtarget=$(find_logactionchain $xtarget) + do_it No + else + xtarget1=$(map_old_action ${xtarget%%:*}) + + case $xtarget1 in + */*) + xparam=${xtarget1#*/} + xtarget1=${xtarget1%%/*} + xtarget=$(substitute_action $xtarget1 $xtarget) + ;; + *) + xparam= + ;; + esac + + f=macro.$xtarget1 + + 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 + fi + ;; + + esac + done < $TMP_DIR/rules + + case $SECTION in + ESTABLISHED) + finish_section ESTABLISHED,RELATED + ;; + RELATED) + finish_section RELATED + ;; + esac + + SECTION=DONE +} + +# +# 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". +# +process_tos_rule() { + # + # 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 + error_message "WARNING: Undefined Source Zone - rule \"$rule\" ignored" + return + fi + + [ -n "$src" ] && case "$src" in + *.*.*|+*|!+*) + # + # IP Address or networks + # + src="$(source_ip_range $src)" + ;; + ~*) + src=$(mac_match $src) + ;; + *) + # + # Assume that this is a device name + # + if ! verify_interface $src ; then + error_message "WARNING: Unknown Interface in rule \"$rule\" ignored" + return + fi + + src="$(match_source_dev $src)" + ;; + esac + + # + # 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 \ + "WARNING: Undefined Destination Zone - rule \"$rule\" ignored" + return + fi + + [ -n "$dst" ] && case "$dst" in + *.*.*|+*|!+*) + # + # IP Address or networks + # + ;; + *) + # + # Assume that this is a device name + # + error_message \ + "WARNING: Invalid Destination - rule \"$rule\" ignored" + return + ;; + esac + + # + # 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 + dest="$(dest_ip_range $dest)" + + case $srczone in + $FW) + run_iptables2 -t mangle -A outtos \ + $protocol $dest $dports $sports $tos + ;; + all|ALL) + run_iptables2 -t mangle -A outtos \ + $protocol $dest $dports $sports $tos + run_iptables2 -t mangle -A pretos \ + $protocol $dest $dports $sports $tos + ;; + *) + if [ -n "$src" ]; then + run_iptables2 -t mangle -A pretos $src \ + $protocol $dest $dports $sports $tos + else + eval interfaces=\$${srczone}_interfaces + + for interface in $interfaces; do + run_iptables2 -t mangle -A pretos -i $interface \ + $protocol $dest $dports $sports $tos + done + fi + ;; + esac + done + + progress_message " Rule \"$rule\" $DONE." +} + +# +# Process the tos file +# +process_tos() # $1 = name of tos file +{ + progress_message2 "$DOING $1..." + + strip_file tos $1 + + if [ -s $TMP_DIR/tos ] ; then + createmanglechain pretos + createmanglechain 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 + + run_iptables -t mangle -A PREROUTING -j pretos + run_iptables -t mangle -A OUTPUT -j outtos + fi +} + +# +# Display elements of a list with leading white space +# +display_list() # $1 = List Title, rest of $* = list to display +{ + [ $# -gt 1 ] && echo " $*" +} + +policy_rules() # $1 = chain to add rules to + # $2 = policy + # $3 = loglevel +{ + local target="$2" + + case "$target" in + ACCEPT) + [ -n "$ACCEPT_common" ] && run_iptables -A $1 -j $ACCEPT_common + ;; + DROP) + [ -n "$DROP_common" ] && run_iptables -A $1 -j $DROP_common + ;; + REJECT) + [ -n "$REJECT_common" ] && run_iptables -A $1 -j $REJECT_common + target=reject + ;; + QUEUE) + [ -n "$QUEUE_common" ] && run_iptables -A $1 -j $QUEUE_common + ;; + CONTINUE) + target= + ;; + *) + fatal_error "Invalid policy ($policy) for $1" + ;; + esac + + if [ $# -eq 3 -a "x${3}" != "x-" ]; then + log_rule $3 $1 $2 + fi + + [ -n "$target" ] && run_iptables -A $1 -j $target +} + +# +# 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. +# +default_policy() # $1 = client $2 = server +{ + local chain="${1}2${2}" + local policy= + local loglevel= + local chain1 + + jump_to_policy_chain() { + # + # Add a jump to from the canonical chain to the policy chain. On return, + # $chain is set to the name of the policy chain + # + run_iptables -A $chain -j $chain1 + chain=$chain1 + } + + report_syn_flood_protection() + { + progress_message " Enabled SYN flood protection" + } + + apply_default() + { + # + # Generate policy file column values from the policy chain + # + eval policy=\$${chain1}_policy + eval loglevel=\$${chain1}_loglevel + eval synparams=\$${chain1}_synparams + # + # Add the appropriate rules to the canonical chain ($chain) to enforce + # the specified policy + + if [ "$chain" = "$chain1" ]; then + # + # The policy chain is the canonical chain; add policy rule to it + # The syn flood jump has already been added if required. + # + policy_rules $chain $policy $loglevel + else + # + # The policy chain is different from the canonical chain -- approach + # depends on the policy + # + case $policy in + ACCEPT|QUEUE) + if [ -n "$synparams" ]; then + # + # To avoid double-counting SYN packets, enforce the policy + # in this chain. + # + report_syn_flood_protection + policy_rules $chain $policy $loglevel + else + # + # No problem with double-counting so just jump to the + # policy chain. + # + jump_to_policy_chain + fi + ;; + CONTINUE) + # + # Silly to jump to the policy chain -- add any logging + # rules and enable SYN flood protection if requested + # + [ -n "$synparams" ] && \ + report_syn_flood_protection + policy_rules $chain $policy $loglevel + ;; + *) + # + # DROP or REJECT policy -- enforce in the policy chain and + # enable SYN flood protection if requested. + # + [ -n "$synparams" ] && \ + report_syn_flood_protection + jump_to_policy_chain + ;; + esac + fi + + progress_message " Policy $policy for $1 to $2 using chain $chain" + } + + eval chain1=\$${1}2${2}_policychain + + if [ -n "$chain1" ]; then + apply_default $1 $2 + else + fatal_error "No default policy for zone $1 to zone $2" + fi +} + +# +# Complete a standard chain +# +# - run any supplied user exit +# - search the policy file for an applicable policy and add rules as +# appropriate +# - If no applicable policy is found, add rules for an assummed +# policy of DROP INFO +# +complete_standard_chain() # $1 = chain, $2 = source zone, $3 = destination zone +{ + local policy= + local loglevel= + local policychain= + + run_user_exit $1 + + eval policychain=\$${2}2${3}_policychain + + if [ -n "$policychain" ]; then + eval policy=\$${policychain}_policy + eval loglevel=\$${policychain}_loglevel + eval + + policy_rules $1 $policy $loglevel + else + policy_rules $1 DROP info + fi +} + +# +# 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 +# +rules_chain() # $1 = source zone, $2 = destination zone +{ + local chain=${1}2${2} local policy + + havechain $chain && { echo $chain; return; } + + [ "$1" = "$2" ] && { echo ACCEPT; return; } + + eval chain=\$${chain}_policychain + + eval policy=\$${chain}_policy + + if [ "$policy" != CONTINUE ] ; then + [ -n "$chain" ] && { echo $chain; return; } + fatal_error "No policy defined for zone $1 to zone $2" + fi +} + +# +# Set up Routing +# +setup_routes() +{ + + run_iptables -t mangle -A PREROUTING -m connmark ! --mark 0 -j CONNMARK --restore-mark + run_iptables -t mangle -A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark + createmanglechain routemark + + for interface in $ROUTEMARK_INTERFACES ; do + + iface=$(chain_base $interface) + eval mark_value=\$${iface}_routemark + + 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 + + done + + run_iptables -t mangle -A routemark -m mark ! --mark 0 -j CONNMARK --save-mark --mask 255 + +} + +# +# Set up Source NAT (including masquerading) +# +setup_masq() +{ + do_ipsec_options() { + local options="$(separate_list $ipsec)" option + 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 + } + + setup_one() { + 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 + + case $fullinterface in + +*) + pre_nat=Yes + fullinterface=${fullinterface#+} + ;; + esac + + case $fullinterface in + *::*) + add_snat_aliases= + destnets="${fullinterface##*:}" + fullinterface="${fullinterface%:*}" + ;; + *:*:*) + # Both alias name and networks + destnets="${fullinterface##*:}" + fullinterface="${fullinterface%:*}" + ;; + *:) + add_snat_aliases= + fullinterface=${fullinterface%:} + ;; + *:*) + # Alias name OR networks + case ${fullinterface#*:} in + *.*) + # It's a networks + destnets="${fullinterface#*:}" + fullinterface="${fullinterface%:*}" + ;; + *) + #it's an alias name + ;; + esac + ;; + *) + ;; + esac + + interface=${fullinterface%:*} + + if ! list_search $interface $ALL_INTERFACES; then + fatal_error "Unknown interface $interface" + fi + + if [ "$networks" = "${networks%!*}" ]; then + nomasq= + else + nomasq="${networks#*!}" + networks="${networks%!*}" + fi + + source="${networks:=0.0.0.0/0}" + + detectinterface= + + case $source in + *.*.*|+*|!+*) + ;; + *) + detectinterface=$networks + networks= + ;; + esac + + [ "x$addresses" = x- ] && addresses= + + if [ -n "$addresses" -a -n "$add_snat_aliases" ]; then + for address in $(separate_list $addresses); do + address=${address%:)} + if [ -n "$address" ]; then + for addr in $(ip_range_explicit ${address%:*}) ; do + if ! list_search $addr $ALIASES_TO_ADD; then + [ -n "$RETAIN_ALIASES" ] || save_command qt ip addr del $addr dev $interface + ALIASES_TO_ADD="$ALIASES_TO_ADD $addr $fullinterface" + case $fullinterface in + *:*) + fullinterface=${fullinterface%:*}:$((${fullinterface#*:} + 1 )) + ;; + esac + fi + done + fi + done + fi + + [ "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 + *:*) + 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 + ;; + *) + if [ -n "$MULTIPORT" ]; then + [ $listcount -le 15 ] || fatal_error "More than 15 entries in port list ($ports)" + 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 + + proto="-p $proto" + else + displayproto="(all)" + [ -n "$ports" ] && fatal_error "Ports only allowed with UDP or TCP ($ports)" + fi + + destination=${destnets:=0.0.0.0/0} + + [ -z "$pre_nat" ] && chain=$(masq_chain $interface) || chain=$(snat_chain $interface) + + ensurenatchain $chain + + case $destnets in + !*) + destnets=${destnets#!} + + build_exclusion_chain newchain nat "$nomasq" "$destnets" + + if [ -n "$networks" ]; then + for s in $networks; do + addnatrule $chain $(source_ip_range $s) $proto $ports $policy -j $newchain + done + networks= + elif [ -n "$detectinterface" ]; then + cat >> $RESTOREBASE << __EOF__ + +${INDENT}networks="\$(get_routed_networks $detectinterface)" + +${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" + +${INDENT}for network in \$networks; do +${INDENT} run_iptables -t nat -A $chain -s \$network $proto $ports $policy -j $newchain +${INDENT}done + +__EOF__ + else + addnatrule $chain -j $newchain + fi + + chain=$newchain + destnets=0.0.0.0/0 + proto= + ports= + policy= + + [ -n "$nomasq" ] && source="$source except $nomasq" + ;; + *) + if [ -n "$nomasq" ]; then + build_exclusion_chain newchain nat $nomasq + + 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 + elif [ -n "$detectinterface" ]; then + cat >> $RESTOREBASE << __EOF__ + +${INDENT}networks="\$(get_routed_networks $detectinterface)" + +${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" + +${INDENT}for network in \$networks; do +__EOF__ + for destnet in $(separate_list $destnets); do + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -t nat -A $chain -s \$network $(dest_ip_range $destnet) $proto $sports $policy -j $netchain +__EOF__ + done + cat >> $RESTOREBASE << __EOF__ + +${INDENT}done +__EOF__ + else + for destnet in $(separate_list $destnets); do + addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $newchain + done + fi + + chain=$newchain + networks= + destnets=0.0.0.0/0 + proto= + ports= + policy= + source="$source except $nomasq" + fi + + ;; + esac + + addrlist= + target=MASQUERADE + + if [ -n "$addresses" ]; then + 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 + fi + + if [ -n "$networks" ]; then + for network in $networks; do + for destnet in $(separate_list $destnets); do + addnatrule $chain $(both_ip_ranges $network $destnet) $proto $ports $policy -j $target $addrlist + done + + if [ -n "$addresses" ]; then + progress_message " To $destination $displayproto from $network through ${interface} using $addresses" + else + progress_message " To $destination $displayproto from $network through ${interface}" + fi + done + elif [ -n "$detectinterface" ]; then + cat >> $RESTOREBASE << __EOF__ + +${INDENT}networks="\$(get_routed_networks $detectinterface)" + +${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" + +${INDENT}for network in \$networks; do +__EOF__ + for destnet in $(separate_list $destnets); do + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -t nat -A $chain -s \$network $(dest_ip_range $destnet) $proto $ports $policy -j $target $addrlist +__EOF__ + done + + if [ -n "$addresses" ]; then + message=" To $destination $displayproto from \$network through ${interface} using $addresses" + else + message=" To $destination $displayproto from \$network through ${interface}" + fi + + cat >> $RESTOREBASE << __EOF__ +${INDENT} progress_message "$message" +${INDENT}done + +__EOF__ + + else + for destnet in $(separate_list $destnets); do + addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $target $addrlist + done + + 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 + fi + + } + + strip_file masq $1 + + if [ -n "$NAT_ENABLED" ]; then + progress_message2 "Masqueraded Networks and Hosts:" + save_progress_message "Setting up Masquerading/SNAT..." + fi + + while read fullinterface networks addresses proto ports ipsec; do + expandv fullinterface networks addresses proto ports ipsec + if [ -n "$NAT_ENABLED" ]; then + setup_one + else + error_message "WARNING: NAT disabled; masq rule ignored" + fi + done < $TMP_DIR/masq +} + +# +# Add a record to the blacklst chain +# +# $source = address match +# $proto = protocol selector +# $dport = destination port selector +# +add_blacklist_rule() { + if [ -n "$BLACKLIST_LOGLEVEL" ]; then + log_rule $BLACKLIST_LOGLEVEL blacklst $BLACKLIST_DISPOSITION $(fix_bang $source $proto $dport) + fi + + run_iptables2 -A blacklst $source $proto $dport -j $disposition +} + +# +# Process a record from the blacklist file +# +# $networks = address/networks +# $protocol = Protocol Number/Name +# $port = Port Number/Name +# +process_blacklist_rec() { + local source + local addr + local proto + local dport + local temp + local setname + + for addr in $(separate_list $networks); do + case $addr in + -) + source= + ;; + ~*) + addr=$(echo $addr | sed 's/~//;s/-/:/g') + source="--match mac --mac-source $addr" + ;; + *) + source="$(source_ip_range $addr)" + ;; + esac + + if [ -n "$protocol" ]; then + proto=" -p $protocol " + + case $protocol in + tcp|TCP|6|udp|UDP|17) + if [ -n "$ports" ]; then + if [ -n "$MULTIPORT" -a \ + "$ports" != "${ports%,*}" -a \ + "$ports" = "${ports%:*}" -a \ + $(list_count $ports) -le 15 ] + then + dport="-m multiport --dports $ports" + add_blacklist_rule + else + for dport in $(separate_list $ports); do + dport="--dport $dport" + add_blacklist_rule + done + fi + else + add_blacklist_rule + fi + ;; + icmp|ICMP|0) + if [ -n "$ports" ]; then + for dport in $(separate_list $ports); do + dport="--icmp-type $dport" + add_blacklist_rule + done + else + add_blacklist_rule + fi + ;; + *) + add_blacklist_rule + ;; + esac + else + add_blacklist_rule + fi + + if [ -n "$ports" ]; then + addr="$addr $protocol $ports" + elif [ -n "$protocol" ]; then + addr="$addr $protocol" + fi + + progress_message " $addr added to Black List" + done +} + +# +# Setup the Black List +# +setup_blacklist() { + local hosts="$(find_hosts_by_option blacklist)" + local f=$(find_file blacklist) + local disposition=$BLACKLIST_DISPOSITION + local ipsec policy + + if [ -n "$hosts" -a -f $f ]; then + progress_message2 "Setting up Blacklisting..." + + [ $COMMAND = restore ] && save_progress_message "Setting up Blacklisting..." + + strip_file blacklist $f + + createchain blacklst no + + [ -n "$BLACKLISTNEWONLY" ] && state="-m state --state NEW,INVALID" || state= + + for host in $hosts; do + ipsec=${host%^*} + host=${host#*^} + [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= + interface=${host%%:*} + network=${host#*:} + + for chain in $(first_chains $interface); do + run_iptables -A $chain $state $(match_source_hosts $network) $policy -j blacklst + done + + [ $network = 0/0.0.0.0 ] && network= || network=":$network" + + progress_message " Blacklisting enabled on ${interface}${network}" + done + + [ "$disposition" = REJECT ] && disposition=reject + + if [ -z "$DELAYBLACKLISTLOAD" ]; then + while read networks protocol ports; do + expandv networks protocol ports + process_blacklist_rec + done < $TMP_DIR/blacklist + fi + fi +} + +# +# Refresh the Black List +# +refresh_blacklist() { + local f=$(find_file blacklist) + local disposition=$BLACKLIST_DISPOSITION + + if qt $IPTABLES -L blacklst -n ; then + progress_message2 "Loading Black List..." + + strip_file blacklist $f + + [ "$disposition" = REJECT ] && disposition=reject + + run_iptables -F blacklst + + while read networks protocol ports; do + expandv networks protocol ports + process_blacklist_rec + done < $TMP_DIR/blacklist + fi +} + +# +# Verify the Black List +# +validate_blacklist() { + local f=$(find_file blacklist) + local disposition=$BLACKLIST_DISPOSITION + + progress_message2 "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 +} + +# +# 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" +} + +# Verify that the 'ip' program is installed + +verify_ip() { + qt ip link ls ||\ + startup_error "Shorewall $VERSION requires the iproute package ('ip' utility)" +} + +# +# 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 +# - Determine the zones +# +initialize_netfilter () { + setup_mss() + { + 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 + } + + report_capabilities + + 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= + + if [ -n "$MACLIST_TTL" -a -z "$RECENT_MATCH" ]; then + startup_error "MACLIST_TTL requires the Recent Match capability which is not present in your Kernel and/or iptables" + fi + + [ -n "$RFC1918_STRICT" -a -z "$CONNTRACK_MATCH" ] && \ + startup_error "RFC1918_STRICT=Yes requires Connection Tracking match" + + progress_message2 "Determining Zones..." + + determine_zones + + if [ $QUIET -lt 2 ]; then + display_list "IPv4 Zones:" $IPV4_ZONES + [ -n "$IPSEC_ZONES" ] && \ + display_list "IPSEC Zones:" $IPSEC_ZONES + display_list "Firewall Zone:" $FW + fi + + progress_message2 "Validating interfaces file..." + + validate_interfaces_file + + progress_message2 "Validating hosts file..." + + validate_hosts_file + + progress_message2 "Validating Policy file..." + + validate_policy + + progress_message2 "Determining Hosts in Zones..." + + determine_interfaces + determine_hosts + + run_user_exit init + + # + # Some files might be large so strip them while the firewall is still running + # (restart command). This reduces the length of time that the firewall isn't + # accepting new connections. + # + + strip_file rules + strip_file proxyarp + strip_file maclist + strip_file nat + strip_file netmap + + progress_message2 "Pre-processing Actions..." + process_actions1 + + TERMINATOR=fatal_error + + 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 + + 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 + + [ -n "$CLEAR_TC" ] && delete_tc + + progress_message2 "Deleting user chains..." + + save_progress_message "Deleting user chains..." + + exists_INPUT=Yes + exists_OUTPUT=Yes + exists_FORWARD=Yes + + process_criticalhosts + + if [ -n "$CRITICALHOSTS" ]; then + + setpolicy INPUT ACCEPT + setpolicy OUTPUT ACCEPT + setpolicy FORWARD DROP + + deleteallchains + + enable_critical_hosts + + setpolicy INPUT DROP + setpolicy OUTPUT DROP + + [ -n "$CLAMPMSS" ] && setup_mss + + setcontinue FORWARD + setcontinue INPUT + setcontinue OUTPUT + else + + setpolicy INPUT DROP + setpolicy OUTPUT DROP + setpolicy FORWARD DROP + + deleteallchains + + [ -n "$CLAMPMSS" ] && setup_mss + + setcontinue FORWARD + setcontinue INPUT + setcontinue OUTPUT + fi + + f=$(find_file ipsets) + + if [ -f $f ]; then + progress_message2 "Processing $f ..." + save_progress_message "Restoring IPSETS..." + save_command "ipset -U :all: :all:" + save_command "ipset -F" + save_command "ipset -X" + save_command "ipset -R < $f" + fi + + run_user_exit continue + + f=$(find_file routestopped) + + progress_message2 "$DOING $f ..." + + strip_file routestopped $f + + process_routestopped -A + + if [ -n "$DISABLE_IPV6" ]; then + save_command disable_ipv6 + fi + + save_progress_message "Enabling Loopback and DNS Lookups" + + # + # Enable the Loopback interface for now + # + run_iptables -A INPUT -i lo -j ACCEPT + run_iptables -A OUTPUT -o lo -j ACCEPT + + # + # Allow DNS lookups during startup for FQDNs + # + + for chain in INPUT OUTPUT FORWARD; do + run_iptables -A $chain -p udp --dport 53 -j ACCEPT + done + + accounting_file=$(find_file accounting) + + [ -f $accounting_file ] && setup_accounting $accounting_file + + createchain reject no + createchain dynamic no + createchain smurfs no + + if [ -f /var/lib/shorewall/save ]; then + progress_message2 "Setting up dynamic rules..." + + save_progress_message "Restoring dynamic rules..." + + if [ -f /var/lib/shorewall/save ]; then + while read target ignore1 ignore2 address rest; do + case $target in + DROP|reject) + run_iptables -A dynamic -s $address -j $target + ;; + *) + ;; + esac + done < /var/lib/shorewall/save + fi + fi + + [ -n "$BLACKLISTNEWONLY" ] && state="-m state --state NEW,INVALID" || state= + + progress_message2 "Creating Interface Chains..." + + save_progress_message "Creating Interface Chains..." + + for interface in $ALL_INTERFACES; do + 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 + done +} + +# +# Construct zone-independent rules +# +add_common_rules() { + local savelogparms="$LOGPARMS" + local broadcasts="$(find_broadcasts) 255.255.255.255 224.0.0.0/4" + + drop_broadcasts() { + for interface in $(find_bcastdetect_interfaces); do + cat >> $RESTOREBASE << __EOF__ + +${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do +${INDENT} run_iptables -A reject -d \$address -j DROP +${INDENT}done + +__EOF__ + done + + for address in $broadcasts ; do + run_iptables -A reject -d $address -j DROP + done + } + # + # Populate the smurf chain + # + save_progress_message "Setting up SMURF control..." + + for interface in $(find_bcastdetect_interfaces); do + cat >> $RESTOREBASE << __EOF__ + +${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do +__EOF__ + [ -n "$SMURF_LOG_LEVEL" ] && \ + cat >> $RESTOREBASE << __EOF__ +${INDENT} log_rule $SMURF_LOG_LEVEL smurfs DROP -s \$address +__EOF__ + cat >> $RESTOREBASE << __EOF__ +${INDENT} run_iptables -A smurfs -s \$address -j DROP +${INDENT}done + +__EOF__ + done + + for address in $broadcasts ; do + [ -n "$SMURF_LOG_LEVEL" ] && log_rule $SMURF_LOG_LEVEL smurfs DROP -s $address + run_iptables -A smurfs $(source_ip_range $address) -j DROP + run_iptables -A reject -s $address -j DROP + done + # + # Reject Rules -- Don't respond to broadcasts with an ICMP + # + if [ -n "$USEPKTTYPE" ]; then + run_iptables -A reject -m pkttype --pkt-type broadcast -j DROP + run_iptables -A reject -m pkttype --pkt-type multicast -j DROP + else + drop_broadcasts + fi + # + # Don't feed the smurfs + # + for address in $broadcasts ; do + run_iptables -A reject -s $address -j DROP + done + + run_iptables -A reject -p tcp -j REJECT --reject-with tcp-reset + run_iptables -A reject -p udp -j REJECT + # + # Not all versions of iptables support these so don't complain if they don't work + # + if [ -n "$ENHANCED_REJECT" ]; then + run_iptables -A reject -p icmp -j REJECT --reject-with icmp-host-unreachable + run_iptables -A reject -j REJECT --reject-with icmp-host-prohibited + else + run_iptables -A reject -j REJECT + fi + + # + # Create common action chains + # + for action in $USEDACTIONS; do + createactionchain $action + done + + run_user_exit initdone + + # + # Process Black List + # + save_progress_message "Setting up Black List..." + + setup_blacklist + + # + # SMURFS + # + hosts=$(find_hosts_by_option nosmurfs) + + if [ -n "$hosts" ]; then + + progress_message2 "Adding Anti-smurf Rules" + + save_progress_message "Adding Anti-smurf Jumps..." + + for host in $hosts; do + ipsec=${host%^*} + host=${host#*^} + [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= + interface=${host%%:*} + network=${host#*:} + + for chain in $(first_chains $interface); do + run_iptables -A $chain -m state --state NEW,INVALID $(match_source_hosts $network) $policy -j smurfs + done + done + fi + # + # DHCP + # + interfaces=$(find_interfaces_by_option dhcp) + + if [ -n "$interfaces" ]; then + + progress_message2 "Adding rules for DHCP" + + save_progress_message "Setting up rules for DHCP..." + + for interface in $interfaces; do + if [ -n "$BRIDGING" ]; then + is_bridge=$( brctl show $interface 2> /dev/null | grep ^$interface[[:space:]] ) + [ -n "$is_bridge" ] && \ + do_iptables -A $(forward_chain $interface) -p udp -o $interface --dport 67:68 -j ACCEPT + fi + run_iptables -A $(input_chain $interface) -p udp --dport 67:68 -j ACCEPT + run_iptables -A OUTPUT -o $interface -p udp --dport 67:68 -j ACCEPT + done + fi + # + # RFC 1918 + # + hosts="$(find_hosts_by_option norfc1918)" + + if [ -n "$hosts" ]; then + progress_message2 "Enabling RFC1918 Filtering" + + save_progress_message "Setting up RFC1918 Filtering..." + + strip_file rfc1918 + + createchain norfc1918 no + + createchain rfc1918 no + + log_rule $RFC1918_LOG_LEVEL rfc1918 DROP + + run_iptables -A rfc1918 -j DROP + + chain=norfc1918 + + if [ -n "$RFC1918_STRICT" ]; then + # + # We'll generate two chains - one for source and one for destination + # + chain=rfc1918d + createchain $chain no + elif [ -n "$MANGLE_ENABLED" -a -z "$CONNTRACK_MATCH" ]; then + # + # Mangling is enabled but conntrack match isn't available -- + # 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 + # + # Also add a chain to log and drop any RFC1918 packets that we find + # + createmanglechain man1918 + createmanglechain rfc1918 + log_rule $RFC1918_LOG_LEVEL rfc1918 DROP -t mangle + run_iptables -t mangle -A rfc1918 -j DROP + fi + + while read networks target; do + case $target in + logdrop) + target=rfc1918 + s_target=rfc1918 + ;; + DROP) + s_target=DROP + ;; + RETURN) + [ -n "$RFC1918_STRICT" ] && s_target=rfc1918d || s_target=RETURN + ;; + *) + fatal_error "Invalid target ($target) for $networks" + ;; + esac + + for network in $(separate_list $networks); do + run_iptables2 -A norfc1918 $(source_ip_range $network) -j $s_target + + 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 + done < $TMP_DIR/rfc1918 + + [ -n "$RFC1918_STRICT" ] && run_iptables -A norfc1918 -j rfc1918d + + for host in $hosts; do + ipsec=${host%^*} + host=${host#*^} + [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= + interface=${host%%:*} + networks=${host#*:} + + for chain in $(first_chains $interface); do + run_iptables -A $chain -m state --state NEW $(match_source_hosts $networks) $policy -j norfc1918 + done + + [ -n "$MANGLE_ENABLED" -a -z "$CONNTRACK_MATCH" ] && \ + run_iptables -t mangle -A PREROUTING -m state --state NEW -i $interface $(match_source_hosts $networks) -j man1918 + done + fi + + hosts=$(find_hosts_by_option tcpflags) + + if [ -n "$hosts" ]; then + progress_message2 "Setting up TCP Flags checking..." + + save_progress_message "Setting up TCP Flags checking..." + + createchain tcpflags no + + if [ -n "$TCP_FLAGS_LOG_LEVEL" ]; then + createchain logflags no + + savelogparms="$LOGPARMS" + + [ "$TCP_FLAGS_LOG_LEVEL" = ULOG ] || LOGPARMS="$LOGPARMS --log-ip-options" + + log_rule $TCP_FLAGS_LOG_LEVEL logflags $TCP_FLAGS_DISPOSITION + + LOGPARMS="$savelogparms" + + case $TCP_FLAGS_DISPOSITION in + REJECT) + run_iptables -A logflags -j REJECT --reject-with tcp-reset + ;; + *) + 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 + # + # 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. + # + run_iptables -A tcpflags -p tcp --syn --sport 0 $disposition + + for host in $hosts; do + ipsec=${host%^*} + host=${host#*^} + [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= + interface=${host%%:*} + network=${host#*:} + + for chain in $(first_chains $interface); do + run_iptables -A $chain -p tcp $(match_source_hosts $network) $policy -j tcpflags + done + done + fi + # + # ARP Filtering + # + save_progress_message "Setting up ARP filtering..." + + cat >> $RESTOREBASE << __EOF__ +${INDENT}for f in /proc/sys/net/ipv4/conf/*; do +${INDENT} [ -f \$f/arp_filter ] && echo 0 > \$f/arp_filter +${INDENT} [ -f \$f/arp_ignore ] && echo 0 > \$f/arp_ignore +${INDENT}done + +__EOF__ + + interfaces=$(find_interfaces_by_option arp_filter) + interfaces1=$(find_interfaces_by_option1 arp_ignore) + + if [ -n "${interfaces}${interfaces1}" ]; then + progress_message2 "Setting up ARP Filtering..." + + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/arp_filter + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f $file ]; then +${INDENT} echo 1 > $file +${INDENT}else +${INDENT} error_message "WARNING: Cannot set ARP filtering on $interface" +${INDENT}fi +__EOF__ + done + + for interface in $interfaces1; do + file=/proc/sys/net/ipv4/conf/$interface/arp_ignore + eval value="\$$(chain_base $interface)_arp_ignore" + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f $file ]; then +${INDENT} echo $value > $file +${INDENT}else +${INDENT} error_message "WARNING: Cannot set ARP filtering on $interface" +${INDENT}fi +__EOF__ + done + fi + # + # Route Filtering + # + interfaces="$(find_interfaces_by_option routefilter)" + + if [ -n "$interfaces" -o -n "$ROUTE_FILTER" ]; then + progress_message2 "Setting up Kernel Route Filtering..." + + save_progress_message "Setting up Route Filtering..." + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}for f in /proc/sys/net/ipv4/conf/*; do +${INDENT} [ -f \$f/log_martians ] && echo 0 > \$f/rp_filter +${INDENT}done + +__EOF__ + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/rp_filter + + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f $file ]; then +${INDENT} echo 1 > $file +${INDENT}else +${INDENT} error_message "WARNING: Cannot set route filtering on $interface" +${INDENT}fi +__EOF__ + done + + save_command "echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter" + + if [ -n "$ROUTE_FILTER" ]; then + save_command "echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter" + save_command "echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter" + fi + + save_command "[ -n \"\$NOROUTES\" ] || ip route flush cache" + fi + + # + # Martian Logging + # + interfaces="$(find_interfaces_by_option logmartians)" + + if [ -n "$interfaces" -o -n "$LOG_MARTIANS" ]; then + progress_message2 "Setting up Martian Logging..." + + save_progress_message "Setting up Martian Logging..." + + cat >> $RESTOREBASE << __EOF__ + +${INDENT}for f in /proc/sys/net/ipv4/conf/*; do +${INDENT} [ -f \$f/log_martians ] && echo 0 > \$f/log_martians +${INDENT}done + +__EOF__ + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/log_martians + + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f $file ]; then +${INDENT} echo 1 > $file +${INDENT}else +${INDENT} error_message "WARNING: Cannot set Martian logging on $interface" +${INDENT}fi +__EOF__ + done + + if [ -n "$LOG_MARTIANS" ]; then + save_command "echo 1 > /proc/sys/net/ipv4/conf/default/log_martians" + save_command "echo 1 > /proc/sys/net/ipv4/conf/all/log_martians" + fi + + fi + + # + # Source Routing + # + save_progress_message "Setting up Accept Source Routing..." + + cat >> $RESTOREBASE << __EOF__ +${INDENT}for f in /proc/sys/net/ipv4/conf/*; do +${INDENT} [ -f \$f/accept_source_route ] && echo 0 > \$f/accept_source_route +${INDENT}done + +__EOF__ + + interfaces=$(find_interfaces_by_option sourceroute) + + if [ -n "$interfaces" ]; then + progress_message2 "Setting up Accept Source Routing..." + + save_progress_message "Setting up Source Routing..." + + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/accept_source_route + + cat >> $RESTOREBASE << __EOF__ +${INDENT}if [ -f $file ]; then +${INDENT} echo 1 > $file +${INDENT}else +${INDENT} error_message "WARNING: Cannot set Accept Source Routing on $interface" +${INDENT}fi +__EOF__ + done + fi + + if [ -n "$DYNAMIC_ZONES" ]; then + echo "Setting up Dynamic Zone Chains..." + + for interface in $ALL_INTERFACES; do + 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 + fi + # + # UPnP + # + interfaces=$(find_interfaces_by_option upnp) + + if [ -n "$interfaces" ]; then + progress_message2 "Setting up UPnP..." + + save_progress_message "Setting up UPnP..." + + createnatchain UPnP + + for interface in $interfaces; do + run_iptables -t nat -A PREROUTING -i $interface -j UPnP + done + fi + + setup_forwarding +} + +# +# Scan the policy file defining the necessary chains +# Add the appropriate policy rule(s) to the end of each canonical chain +# +apply_policy_rules() { + # + # Create policy chains + # + for chain in $ALL_POLICY_CHAINS; do + eval policy=\$${chain}_policy + eval loglevel=\$${chain}_loglevel + eval optional=\$${chain}_is_optional + + if [ "$policy" != NONE ]; then + if ! havechain $chain && [ -z "$optional" -a "$policy" != CONTINUE ]; then + # + # The chain doesn't exist. Create the chain and add policy + # rules + # + createchain $chain yes + # + # 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 + # + case $chain in + all2*|*2all) + policy_rules $chain $policy $loglevel + ;; + esac + fi + fi + done + + # + # Add policy rules to canonical chains + # + for zone in $FW $ZONES; do + for zone1 in $FW $ZONES; do + chain=${zone}2${zone1} + if havechain $chain; then + run_user_exit $chain + default_policy $zone $zone1 + fi + done + done +} + +# +# Activate the rules +# +activate_rules() +{ + local PREROUTING_rule=1 + local POSTROUTING_rule=1 + # + # 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 + + if havenatchain $destchain ; then + 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 + fi + } + + # + # Jump to a RULES chain from one of the builtin nat chains. These jumps are + # are inserted before jumps to one-to-one NAT chains. + # + addrulejump() # $1 = BUILTIN chain, $2 = user chain, $3 - * other arguments + { + local sourcechain=$1 destchain=$2 + shift + shift + + if havenatchain $destchain; then + eval run_iptables2 -t nat -I $sourcechain \ + \$${sourcechain}_rule $@ -j $destchain + eval ${sourcechain}_rule=\$\(\(\$${sourcechain}_rule + 1\)\) + 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 + + fi + } + + # + # 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 + } + # + # Add jumps to early SNAT chains + # + for interface in $ALL_INTERFACES; do + addnatjump POSTROUTING $(snat_chain $interface) -o $interface + done + # + # Add jumps for dynamic nat chains + # + [ -n "$DYNAMIC_ZONES" ] && for interface in $ALL_INTERFACES ; do + addrulejump PREROUTING $(dynamic_in $interface) -i $interface + done + # + # Add jumps from the builtin chains to the nat chains + # + addnatjump PREROUTING nat_in + addnatjump POSTROUTING nat_out + + for interface in $ALL_INTERFACES; do + addnatjump PREROUTING $(input_chain $interface) -i $interface + addnatjump POSTROUTING $(output_chain $interface) -o $interface + done + + > $STATEDIR/chains + echo "$FW firewall" > $STATEDIR/zones + # + # Create forwarding chains for complex zones and generate jumps for IPSEC source hosts to that chain. + # + for zone in $ZONES; do + if eval test -n \"\$${zone}_is_complex\" ; then + frwd_chain=${zone}_frwd + createchain $frwd_chain No + + if [ -n "$POLICY_MATCH" ]; then + # + # 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. + # + eval is_ipsec=\$${zone}_is_ipsec + + if [ -n "$is_ipsec" ]; then + eval source_hosts=\$${zone}_hosts + [ -n "$DYNAMIC_ZONES" ] && create_zone_dyn_chain $zone $frwd_chain + else + eval source_hosts=\$${zone}_ipsec_hosts + [ -n "$DYNAMIC_ZONES" -a -n "$source_hosts" ] && create_zone_dyn_chain $zone $frwd_chain + fi + + for host in $source_hosts; do + interface=${host%%:*} + networks=${host#*:} + + run_iptables2 -A $(forward_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $frwd_chain + done + fi + fi + done + + for zone in $ZONES; do + eval source_hosts=\$${zone}_hosts + + chain1=$(rules_chain $FW $zone) + chain2=$(rules_chain $zone $FW) + + eval complex=\$${zone}_is_complex + eval type=\$${zone}_type + + [ -n "$complex" ] && frwd_chain=${zone}_frwd + + echo $zone $type $source_hosts >> $STATEDIR/zones + + if [ -n "$DYNAMIC_ZONES" ]; then + echo "$FW $zone $chain1" >> /var/lib/shorewall/chains + echo "$zone $FW $chain2" >> /var/lib/shorewall/chains + fi + + need_broadcast= + + for host in $source_hosts; do + interface=${host%%:*} + networks=${host#*:} + + [ -n "$chain1" ] && run_iptables2 -A OUTPUT -o $interface $(match_dest_hosts $networks) $(match_ipsec_out $zone $host) -j $chain1 + + # + # Add jumps from the builtin chain for DNAT rules + # + addrulejump PREROUTING $(dnat_chain $zone) -i $interface $(match_source_hosts $networks) $(match_ipsec_in $zone $host) + + [ -n "$chain2" ] && run_iptables2 -A $(input_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $chain2 + + 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 + + case $networks in + *.*.*.*|+*) + 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 + done + + 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 + + eval policy=\$${zone}2${zone1}_policy + + [ "$policy" = NONE ] && continue + + eval dest_hosts=\$${zone1}_hosts + + chain="$(rules_chain $zone $zone1)" + + [ -z "$chain" ] && continue # CONTINUE policy and there is no canonical chain. + + [ -n "$DYNAMIC_ZONES" ] && echo "$zone $zone1 $chain" >> /var/lib/shorewall/chains + + if [ $zone = $zone1 ]; then + # + # Try not to generate superfluous intra-zone rules + # + eval routeback=\"\$${zone}_routeback\" + 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 + else + routeback= + num_ifaces=0 + fi + + if [ -n "$complex" ]; then + for host1 in $dest_hosts; do + 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 + run_iptables2 -A $frwd_chain -o $interface1 $(match_dest_hosts $networks1) $(match_ipsec_out $zone1 $host1) -j $chain + fi + done + else + for host in $source_hosts; do + interface=${host%%:*} + networks=${host#*:} + + chain3=$(forward_chain $interface) + + for host1 in $dest_hosts; do + interface1=${host1%%:*} + networks1=${host1#*:} + + if [ "$host" != "$host1" ] || list_search $host $routeback; then + run_iptables2 -A $chain3 $(match_source_hosts $networks) -o $interface1 $(match_dest_hosts $networks1) $(match_ipsec_out $zone1 $host1) -j $chain + fi + done + done + fi + done + done + + for interface in $ALL_INTERFACES ; do + 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 + done + + chain=${FW}2${FW} + + if havechain $chain; then + # + # There is a fw->fw chain. Send loopback output through that chain + # + run_iptables -A OUTPUT -o lo -j $chain + # + # And delete the unconditional ACCEPT rule + # + run_iptables -D OUTPUT -o lo -j ACCEPT + fi + + complete_standard_chain INPUT all $FW + complete_standard_chain OUTPUT $FW all + complete_standard_chain FORWARD all all + # + # Remove rules added to keep the firewall alive during [re]start" + # + disable_critical_hosts + + for chain in INPUT OUTPUT FORWARD; do + [ -n "$FASTACCEPT" ] || run_iptables -D $chain -m state --state ESTABLISHED,RELATED -j ACCEPT + run_iptables -D $chain -p udp --dport 53 -j ACCEPT + done + + 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 +} + +# +# Compile a script that will stop the firewall +# +# This function is called by compile_firewall() so all of the overloaded functions +# from that script are available here +# +compile_stop_firewall() { + local IPTABLES_COMMAND="\$IPTABLES" + local INDENT=" " + + cat >> $RESTOREBASE << __EOF__ + +stop_firewall() { + + deletechain() { + qt \$IPTABLES -L \$1 -n && qt \$IPTABLES -F \$1 && qt \$IPTABLES -X \$1 + } + + deleteallchains() { + \$IPTABLES -F + \$IPTABLES -X + } + + setcontinue() { + \$IPTABLES -A \$1 -m state --state ESTABLISHED,RELATED -j ACCEPT + } + + case \$COMMAND in + stop|clear) + ;; + *) + set +x + + [ -n "\${RESTOREFILE:=restore}" ] + + RESTOREPATH=/var/lib/shorewall/\$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; 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 + + determine_capabilities + + 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 + + if [ -f /var/lib/shorewall/proxyarp ]; then + while read address interface external haveroute; do + qt arp -i \$external -d \$address pub + [ -z "\${haveroute}\${NOROUTES}" ] && qt ip route del \$address dev \$interface + done < /var/lib/shorewall/proxyarp + fi + + for f in /proc/sys/net/ipv4/conf/*; do + [ -f \$f/proxy_arp ] && echo 0 > \$f/proxy_arp + done + +__EOF__ + [ -n "$CLEAR_TC" ] && save_command "delete_tc1" + + [ -n "$DISABLE_IPV6" ] && save_command "disable_ipv6" + + process_criticalhosts + + if [ -n "$CRITICALHOSTS" ]; then + if [ -z "$ADMINISABSENTMINDED" ]; then + cat >> $RESTOREBASE << __EOF__ + + for chain in INPUT OUTPUT; do + setpolicy \$chain ACCEPT + done + + setpolicy FORWARD DROP + + deleteallchains + + 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 chain in INPUT OUTPUT; do + setpolicy $\chain DROP + done + +__EOF__ + else + cat >> $RESTOREBASE << __EOF__ + + for chain in INPUT OUTPUT; do + setpolicy \$chain ACCEPT + done + + setpolicy FORWARD DROP + + deleteallchains + + 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 + + setpolicy INPUT DROP + + for chain in INPUT FORWARD; do + setcontinue \$chain + done + +__EOF__ + fi + elif [ -z "$ADMINISABSENTMINDED" ]; then + cat >> $RESTOREBASE << __EOF__ + + for chain in INPUT OUTPUT FORWARD; do + setpolicy \$chain DROP + done + + deleteallchains + +__EOF__ + else + cat >> $RESTOREBASE << __EOF__ + + for chain in INPUT FORWARD; do + setpolicy \$chain DROP + done + + setpolicy OUTPUT ACCEPT + + deleteallchains + + for chain in INPUT FORWARD; do + setcontinue \$chain + done + +__EOF__ + fi + + process_routestopped -A + + save_command "\$IPTABLES -A INPUT -i lo -j ACCEPT" + + [ -z "$ADMINISABSENTMINDED" ] && \ + save_command "\$IPTABLES -A OUTPUT -o lo -j ACCEPT" + + for interface in $(find_interfaces_by_option dhcp); do + save_command "\$IPTABLES -A INPUT -p udp -i $interface --dport 67:68 -j ACCEPT" + [ -z "$ADMINISABSENTMINDED" ] && \ + save_command "\$IPTABLES -A OUTPUT -p udp -o $interface --dport 67:68 -j ACCEPT" + # + # This might be a bridge + # + save_command "\$IPTABLES -A FORWARD -p udp -i $interface -o $interface --dport 67:68 -j ACCEPT" + done + + save_command + + case "$IP_FORWARDING" in + [Oo][Nn]) + save_command "echo 1 > /proc/sys/net/ipv4/ip_forward" + save_command "progress_message2 IP Forwarding Enabled" + ;; + [Oo][Ff][Ff]) + save_command "echo 0 > /proc/sys/net/ipv4/ip_forward" + save_command "progress_message2 IP Forwarding Disabled!" + ;; + esac + + cat >> $RESTOREBASE << __EOF__ + + run_user_exit stopped + + set_state "Stopped" + + logger "Shorewall Stopped" + + 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 + # + kill \$\$ + ;; + esac +} +__EOF__ +} + +# +# Compile a Restore Script +# +compile_firewall() # $1 = File Name +{ + local IPTABLES_COMMAND=run_iptables + local INDENT="" + + outfile=$1 dir= + # + # Overload a couple of functions from the library + # + deletechain() # $1 = name of chain + { + save_command "qt \$IPTABLES -L $1 -n && qt \$IPTABLES -F $1 && qt \$IPTABLES -X $1" + } + + fix_bang() { + echo $@ | sed 's/!/! /g' + } + # + # END OVERLOADED FUNCTIONS + # + + verify_os_version + verify_ip + + [ -d /var/lib/shorewall ] || { mkdir -p /var/lib/shorewall ; chmod 700 /var/lib/shorewall; } + + if [ $COMMAND = compile ]; then + dir=$(dirname $1) + [ -d $dir ] || startup_error "Directory $dir does not exist" + [ -h $dir ] && startup_error "$dir is a Symbolic Link" + [ -d $outfile ] && startup_error "$outfile is a Directory" + [ -h $outfile ] && startup_error "$outfile is a Symbolic Link" + [ -f $outfile -a ! -x $outfile ] && startup_error "$outfile exists and is not a restore file" + + DOING=Compiling + DONE=compiled + else + DOING=Checking + DONE=checked + fi + + RESTOREBASE=$(mktempfile /tmp) + + STATEDIR=$(mktempdir) + + TMP_DIR1=$STATEDIR + + [ -n "$RESTOREBASE" ] || startup_error "Cannot create temporary file in /tmp" + + [ -z "$PROGRAM" ] && save_command "#! $SHOREWALL_SHELL --" + + cat >> $RESTOREBASE << __EOF__ +# +# Compiled startup file generated by Shorewall $VERSION - $(date)" +# +__EOF__ + + if [ -n "$EXPORT" ]; then + cat /usr/share/shorewall/functions >> $RESTOREBASE + else + cat >> $RESTOREBASE << __EOF__ + +. /usr/share/shorewall/functions +__EOF__ + + fi + + compile_stop_firewall + +cat >> $RESTOREBASE << __EOF__ + +setpolicy() { + \$IPTABLES -P \$1 \$2 +} + +clear_firewall() { + stop_firewall + + setpolicy INPUT ACCEPT + setpolicy FORWARD ACCEPT + setpolicy OUTPUT ACCEPT + + run_iptables -F + + echo 1 > /proc/sys/net/ipv4/ip_forward + +__EOF__ + if [ -n "$DISABLE_IPV6" ]; then + cat >> $RESTOREBASE << __EOF__ + if 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 + +__EOF__ + fi + + cat >> $RESTOREBASE << __EOF__ + run_user_exit clear + + set_state "Cleared" + + logger "Shorewall Cleared" +} + +fatal_error() +{ + echo " ERROR: \$@" >&2 + stop_firewall + exit 2 +} + +run_iptables() +{ + if ! \$IPTABLES \$@; then + error_message "ERROR: Command \"\$IPTABLES \$@\" Failed" + stop_firewall + exit 2 + fi +} + +run_ip() +{ + if ! ip \$@; then + error_message "ERROR: Command \"ip \$@\" Failed" + stop_firewall + exit 2 + fi +} + +run_tc() { + if ! tc \$@ ; then + error_message "ERROR: Command \"tc \$@\" Failed" + stop_firewall + exit 2 + fi +} + +initialize() { +__EOF__ + if [ -z "$EXPORT" ]; then + cat >> $RESTOREBASE << __EOF__ + if [ ! -f /usr/share/shorewall/version ] || [ \$(cat /usr/share/shorewall/version) != $VERSION ]; then + error_message "ERROR: This script requires Shorewall version $VERSION" + exit 2 + fi + +__EOF__ + fi + + cat >> $RESTOREBASE << __EOF__ + # + # These variables are required by the library functions called in this script + # + [ -n \${COMMAND:=restart} ] + [ -n \${QUIET:=0} ] + MODULESDIR="$MODULESDIR" + MODULE_SUFFIX="$MODULE_SUFFIX" + LOGLIMIT="$LOGLIMIT" + LOGTAGONLY="$LOGTAGONLY" + LOGRULENUMBERS="$LOGRULENUMBERS" + LOGFORMAT="$LOGFORMAT" + RESTOREFILE="$RESTOREFILE" + VERSION="$VERSION" + CONFIG_PATH="$CONFIG_PATH" + +__EOF__ + if [ -n "$IPTABLES" ]; then + cat >> $RESTOREBASE << __EOF__ + IPTABLES="$IPTABLES" + + [ -e "$IPTABLES" ] || startup_error "\$IPTABLES=$IPTABLES does not exist or is not executable" +__EOF__ + else + cat >> $RESTOREBASE << __EOF__ + IPTABLES=\$(mywhich iptables 2> /dev/null) + + [ -z "\$IPTABLES" ] && startup_error "Can't find iptables executable" +__EOF__ + fi + + cat >> $RESTOREBASE << __EOF__ + + STOPPING= + # + # The library requires that /var/lib/shorewall exist + # + [ -d /var/lib/shorewall ] || mkdir -p /var/lib/shorewall +} + +__EOF__ + save_command "define_firewall() {" + INDENT=" " + +cat >> $RESTOREBASE << __EOF__ + + load_kernel_modules + +__EOF__ + + progress_message2 "Initializing..." + save_progress_message_short "Initializing..." + + initialize_netfilter + + progress_message2 "$DOING Proxy ARP"; setup_proxy_arp + # + # [re]-Establish routing + # + setup_providers $(find_file providers) + [ -n "$ROUTEMARK_INTERFACES" ] && setup_routes + + progress_message2 "$DOING NAT..."; setup_nat + progress_message2 "$DOING NETMAP..."; setup_netmap + progress_message2 "$DOING Common Rules"; add_common_rules + + save_progress_message "Setting up SYN Flood Protection..." + + setup_syn_flood_chains + + save_progress_message "Setting up IPSEC management..." + + setup_ipsec + + maclist_hosts=$(find_hosts_by_option maclist) + + if [ -n "$maclist_hosts" ]; then + save_progress_message "Setting up MAC Filtration..." + setup_mac_lists + fi + + progress_message2 "$DOING $(find_file rules)..." + save_progress_message "Setting up Rules..." + process_rules + + tunnels=$(find_file tunnels) + if [ -f $tunnels ]; then + progress_message2 "$DOING $tunnels..." + save_progress_message "Setting up Tunnels..." + setup_tunnels $tunnels + fi + + save_progress_message "Setting up Actions..." + + progress_message2 "$DOING Actions..."; process_actions2 + process_actions3 + + save_progress_message "Applying Policies..." + + progress_message2 "$DOING $(find_file policy)..."; apply_policy_rules + + masq=$(find_file masq) + if [ -f $masq ]; then + setup_masq $masq + fi + + tos=$(find_file tos) + if [ -f $tos -a -n "$MANGLE_ENABLED" ]; then + save_progress_message "Setting up TOS..." + process_tos $tos + fi + + ecn=$(find_file ecn) + if [ -f $ecn -a -n "$MANGLE_ENABLED" ]; then + save_progress_message "Setting up ECN..." + setup_ecn $ecn + fi + + if [ -n "$MANGLE_ENABLED" ]; then + save_progress_message "Setting up TC Rules..." + setup_tc + fi + + progress_message2 "$DOING Rule Activation..." + save_progress_message "Activating Rules..." + activate_rules + + if [ -n "$ALIASES_TO_ADD" ]; then + save_command add_ip_aliases $ALIASES_TO_ADD + fi + + for file in chains nat proxyarp zones; do + append_file $file + done + + save_command "date > /var/lib/shorewall/restarted" + + run_user_exit start + + [ -n "$DELAYBLACKLISTLOAD" ] && refresh_blacklist + + createchain shorewall no + + save_command set_state "Started" + + run_user_exit started + + INDENT= + save_command "}" + save_command "" + + if [ -n "$PROGRAM" ]; then + cat $(find_file prog.header) $RESTOREBASE $(find_file prog.footer) > $outfile + rm $RESTOREBASE + elif [ $COMMAND = compile ]; then + save_command "initialize" + save_command "define_firewall" + mv -f $RESTOREBASE $outfile + fi + + if [ $COMMAND = check ]; then + rm -f $RESTOREBASE + echo "Shorewall configuration verified" + else + chmod 700 $outfile + + echo "Shorewall configuration compiled to $outfile" + fi + + rm -rf $TMP_DIR + rm -rf $TMP_DIR1 + +} + + +# +# Determine the value for a parameter that defaults to Yes +# +added_param_value_yes() # $1 = Parameter Name, $2 = Parameter value +{ + local val="$2" + + if [ -z "$val" ]; then + echo "Yes" + else case $val in + [Yy][Ee][Ss]) + echo "Yes" + ;; + [Nn][Oo]) + echo "" + ;; + *) + startup_error "Invalid value ($val) for $1" + ;; + esac + fi +} + +# +# Determine the value for a parameter that defaults to No +# +added_param_value_no() # $1 = Parameter Name, $2 = Parameter value +{ + local val="$2" + + if [ -z "$val" ]; then + echo "" + else case $val in + [Yy][Ee][Ss]) + echo "Yes" + ;; + [Nn][Oo]) + echo "" + ;; + *) + startup_error "Invalid value ($val) for $1" + ;; + esac + fi +} + +# +# Initialize this program +# +do_initialize() { + + # Run all utility programs using the C locale + # + # Thanks to Vincent Planchenault for this tip # + + export LC_ALL=C + + # Make sure umask is sane + umask 077 + + PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin + # + # Establish termination function + # + TERMINATOR=startup_error + # + # Clear all configuration variables + # + VERSION= + IPTABLES= + FW= + SUBSYSLOCK= + ALLOWRELATED=Yes + LOGRATE= + LOGBURST= + LOGPARMS= + LOGLIMIT= + ADD_IP_ALIASES= + ADD_SNAT_ALIASES= + TC_ENABLED= + BLACKLIST_DISPOSITION= + BLACKLIST_LOGLEVEL= + CLAMPMSS= + ROUTE_FILTER= + LOG_MARTIANS= + DETECT_DNAT_IPADDRS= + MUTEX_TIMEOUT= + FORWARDPING= + MACLIST_DISPOSITION= + MACLIST_LOG_LEVEL= + TCP_FLAGS_DISPOSITION= + TCP_FLAGS_LOG_LEVEL= + RFC1918_LOG_LEVEL= + MARK_IN_FORWARD_CHAIN= + SHARED_DIR=/usr/share/shorewall + FUNCTIONS= + VERSION_FILE= + LOGFORMAT= + LOGRULENUMBERS= + ADMINISABSENTMINDED= + BLACKLISTNEWONLY= + MODULE_SUFFIX= + ACTIONS= + USEDACTIONS= + SMURF_LOG_LEVEL= + DISABLE_IPV6= + BRIDGING= + DYNAMIC_ZONES= + PKTTYPE= + USEPKTYPE= + RETAIN_ALIASES= + DELAYBLACKLISTLOAD= + LOGTAGONLY= + LOGALLNEW= + RFC1918_STRICT= + MACLIST_TTL= + SAVE_IPSETS= + RESTOREFILE= + MAPOLDACTIONS= + + RESTOREBASE= + TMP_DIR= + ALL_INTERFACES= + ROUTEMARK_INTERFACES= + IPSECMARK=256 + PROVIDERS= + CRITICALHOSTS= + IPSECFILE= + EXCLUSION_SEQ=1 + STOPPING= + HAVE_MUTEX= + ALIASES_TO_ADD= + SECTION=ESTABLISHED + SECTIONS= + ALL_PORTS= + + FUNCTIONS=$SHARED_DIR/functions + + if [ -f $FUNCTIONS ]; then + [ $QUIET -lt 1 ] && echo "Loading $FUNCTIONS..." + . $FUNCTIONS + else + startup_error "$FUNCTIONS does not exist!" + fi + + TMP_DIR=$(mktempdir) + + [ -n "$TMP_DIR" ] && chmod 700 $TMP_DIR || \ + startup_error "Can't create a temporary directory" + + trap "[ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE;rm -rf $TMP_DIR; exit 2" 1 2 3 4 5 6 9 + + ensure_config_path + + VERSION_FILE=$SHARED_DIR/version + + [ -f $VERSION_FILE ] && VERSION=$(cat $VERSION_FILE) + + run_user_exit params + + config=$(find_file shorewall.conf) + + if [ -f $config ]; then + if [ -r $config ]; then + progress_message "Processing $config..." + . $config + else + startup_error "Cannot read $config (Hint: Are you root?)" + fi + else + startup_error "$config does not exist!" + fi + # + # Restore CONFIG_PATH if the shorewall.conf file cleared it + # + ensure_config_path + # + # Determine the capabilities of the installed iptables/netfilter + # We load the kernel modules here to accurately determine + # capabilities when module autoloading isn't enabled. + # + PKTTYPE=$(added_param_value_no PKTTYPE $PKTTYPE) + + [ -n "${MODULE_SUFFIX:=o gz ko o.gz ko.gz}" ] + if [ -z "$EXPORT" ]; then + + load_kernel_modules + + if [ -z "$IPTABLES" ]; then + IPTABLES=$(mywhich iptables 2> /dev/null) + + [ -z "$IPTABLES" ] && startup_error "Can't find iptables executable" + else + [ -e "$IPTABLES" ] || startup_error "\$IPTABLES=$IPTABLES does not exist or is not executable" + fi + determine_capabilities + + [ -d /var/lib/shorewall ] || mkdir -p /var/lib/shorewall + + else + f=$(find_file capabilities) + + [ -f $f ] && . $f || startup_error "The -e flag requires a capabilities file" + fi + + ALLOWRELATED="$(added_param_value_yes ALLOWRELATED $ALLOWRELATED)" + [ -n "$ALLOWRELATED" ] || \ + startup_error "ALLOWRELATED=No is not supported" + ADD_IP_ALIASES="$(added_param_value_yes ADD_IP_ALIASES $ADD_IP_ALIASES)" + + if [ -n "${LOGRATE}${LOGBURST}" ]; then + LOGLIMIT="--match limit" + [ -n "$LOGRATE" ] && LOGLIMIT="$LOGLIMIT --limit $LOGRATE" + [ -n "$LOGBURST" ] && LOGLIMIT="$LOGLIMIT --limit-burst $LOGBURST" + fi + + if [ -n "$IP_FORWARDING" ]; then + case "$IP_FORWARDING" in + [Oo][Nn]|[Oo][Ff][Ff]|[Kk][Ee][Ee][Pp]) + ;; + *) + startup_error "Invalid value ($IP_FORWARDING) for IP_FORWARDING" + ;; + esac + else + IP_FORWARDING=On + fi + + [ -n "${BLACKLIST_DISPOSITION:=DROP}" ] + + case "$CLAMPMSS" in + [0-9]*) + ;; + *) + CLAMPMSS=$(added_param_value_no CLAMPMSS $CLAMPMSS) + ;; + esac + + ADD_SNAT_ALIASES=$(added_param_value_no ADD_SNAT_ALIASES $ADD_SNAT_ALIASES) + ROUTE_FILTER=$(added_param_value_no ROUTE_FILTER $ROUTE_FILTER) + LOG_MARTIANS=$(added_param_value_no LOG_MARTIANS $LOG_MARTIANS) + DETECT_DNAT_IPADDRS=$(added_param_value_no DETECT_DNAT_IPADDRS $DETECT_DNAT_IPADDRS) + FORWARDPING=$(added_param_value_no FORWARDPING $FORWARDPING) + [ -n "$FORWARDPING" ] && \ + startup_error "FORWARDPING=Yes is no longer supported" + + maclist_target=reject + + if [ -n "$MACLIST_DISPOSITION" ] ; then + case $MACLIST_DISPOSITION in + REJECT) + ;; + DROP) + maclist_target=DROP + ;; + ACCEPT) + maclist_target=RETURN + ;; + *) + startup_error "Invalid value ($MACLIST_DISPOSITION) for MACLIST_DISPOSITION" + ;; + esac + else + MACLIST_DISPOSITION=REJECT + fi + + 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 + + [ -n "${RFC1918_LOG_LEVEL:=info}" ] + + MARK_IN_FORWARD_CHAIN=$(added_param_value_no MARK_IN_FORWARD_CHAIN $MARK_IN_FORWARD_CHAIN) + [ -n "$MARK_IN_FORWARD_CHAIN" ] && MARKING_CHAIN=tcfor || MARKING_CHAIN=tcpre + CLEAR_TC=$(added_param_value_yes CLEAR_TC $CLEAR_TC) + + if [ -n "$LOGFORMAT" ]; then + if [ -n "$(echo $LOGFORMAT | grep '%d')" ]; then + LOGRULENUMBERS=Yes + temp=$(printf "$LOGFORMAT" fooxx 1 barxx 2> /dev/null) + if [ $? -ne 0 ]; then + startup_error "Invalid LOGFORMAT string: \"$LOGFORMAT\"" + fi + else + temp=$(printf "$LOGFORMAT" fooxx barxx 2> /dev/null) + if [ $? -ne 0 ]; then + startup_error "Invalid LOGFORMAT string: \"$LOGFORMAT\"" + fi + fi + + [ ${#temp} -le 29 ] || startup_error "LOGFORMAT string is longer than 29 characters: \"$LOGFORMAT\"" + else + LOGFORMAT="Shorewall:%s:%s:" + fi + 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) + STARTUP_ENABLED=$(added_param_value_yes STARTUP_ENABLED $STARTUP_ENABLED) + RETAIN_ALIASES=$(added_param_value_no RETAIN_ALIASES $RETAIN_ALIASES) + [ -n "${ADD_IP_ALIASES}${ADD_SNAT_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) + SAVE_IPSETS=$(added_param_value_no SAVE_IPSETS $SAVE_IPSETS) + MAPOLDACTIONS=$(added_param_value_yes MAPOLDACTIONS $MAPOLDACTIONS) + FASTACCEPT=$(added_param_value_no FASTACCEPT $FASTACCEPT) + + case ${IPSECFILE:=ipsec} in + ipsec|zones) + ;; + *) + startup_error "Invalid value ($IPSECFILE) for IPSECFILE option" + ;; + esac + + 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 + + TC_SCRIPT= + + if [ -n "$TC_ENABLED" ] ; then + case "$TC_ENABLED" in + [Yy][Ee][Ss]) + TC_ENABLED= + TC_SCRIPT=$(find_file tcstart) + [ -f $TC_SCRIPT ] || startup_error "Unable to find tcstart file" + ;; + [Ii][Nn][Tt][Ee][Rr][Nn][Aa][Ll]) + TC_ENABLED=Yes + ;; + [Nn][Oo]) + TC_ENABLED= + ;; + esac + else + TC_ENABLED=Yes + fi + + if [ -n "$TC_ENABLED" ];then + [ -n "$MANGLE_ENABLED" ] || startup_error "Traffic Shaping requires mangle support in your kernel and iptables" + fi + + [ "x${SHOREWALL_DIR}" = "x." ] && SHOREWALL_DIR="$PWD" + + # + # Strip the files that we use often + # + strip_file interfaces + strip_file hosts + # + # Check out the user's shell + # + [ -n "${SHOREWALL_SHELL:=/bin/sh}" ] + + temp=$(decodeaddr 192.168.1.1) + if [ $(encodeaddr $temp) != 192.168.1.1 ]; then + startup_error "Shell $SHOREWALL_SHELL is broken and may not be used with Shorewall" + fi + + rm -f $TMP_DIR/physdev + rm -f $TMP_DIR/iprange +} + +# +# Give Usage Information +# +usage() { + echo "Usage: $0 [debug] check|{generate|compile} }" + 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 "exit 2" 1 2 3 4 5 6 9 + +COMMAND="$1" + +case "$COMMAND" in + + check) + [ $# -ne 1 ] && usage + do_initialize + compile_firewall + ;; + + compile|generate) + [ $# -ne 2 ] && usage + do_initialize + COMMAND=compile + compile_firewall $2 + ;; + + call) + # + # Undocumented way to call functions in /usr/share/shorewall/firewall directly + # + shift + do_initialize + EMPTY= + $@ + ;; + + *) + usage + ;; + +esac diff --git a/Shorewall/firewall b/Shorewall/firewall index 1861429fe..a7b715534 100755 --- a/Shorewall/firewall +++ b/Shorewall/firewall @@ -39,8 +39,6 @@ # shorewall clear Remove all Shorewall chains # and rules/policies. # shorewall refresh . Rebuild the common chain -# shorewall check Verify the more heavily-used -# configuration files. # # Mutual exclusion -- These functions are jackets for the mutual exclusion # routines in $FUNCTIONS. They invoke @@ -61,13 +59,7 @@ my_mutex_off() { fatal_error() # $* = Error Message { echo " ERROR: $@" >&2 - if [ $COMMAND = check -o $COMMAND = compile ]; then - [ -n "$TMP_DIR" ] && rm -rf $TMP_DIR - [ -n "$TMP_DIR1" ] && rm -rf $TMP_DIR1 - [ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE - else - stop_firewall - fi + stop_firewall exit 2 } @@ -157,7 +149,7 @@ append_file() # $1 = File Name } # -# Run iptables -- we define this so that it may be overloaded in the compiler +# Run iptables # do_iptables() { $IPTABLES $@ @@ -256,8 +248,6 @@ finish_chain_section() # $1 = canonical chain $2 = state list ACCEPT|CONTINUE|QUEUE) run_iptables -A $1 -p tcp --syn -j @$1 ;; - *) - esac else run_iptables -A $1 -p tcp --syn -j @$1 @@ -277,16 +267,15 @@ 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 + 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 - fi + done + } # @@ -1117,30 +1106,14 @@ validate_interfaces_file() { dhcp|tcpflags|arp_filter|routefilter|maclist|logmartians|sourceroute|blacklist|proxyarp|nosmurfs|upnp|-) ;; norfc1918) - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ - -${INDENT}addr=\$(ip -f inet addr show $interface 2> /dev/null | grep inet | head -n1) -${INDENT}if [ -n "\$addr" ]; then -${INDENT} addr=\$(echo \$addr | sed 's/inet //;s/\/.*//;s/ peer.*//') -${INDENT} for network in 10.0.0.0/8 176.16.0.0/12 192.168.0.0/16; do -${INDENT} if in_network \$addr \$network; then -${INDENT} fatal_error "The 'norfc1918' option has been specified on an interface with an RFC 1918 address. Interface:$interface" -${INDENT} fi -${INDENT} done -${INDENT}fi - -__EOF__ - else - 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 + 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 ;; arp_ignore=*) @@ -1194,62 +1167,29 @@ setup_providers() local table number mark duplicate interface gateway options provider address copy route loose addresses rulenum pref echobin=$(mywhich echo) balance copy_table() { - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} ip route show table $duplicate | while read net route; do -${INDENT} case \$net in -${INDENT} default|nexthop) -${INDENT} ;; -${INDENT} *) -${INDENT} run_ip route add table $number \$net \$route" -${INDENT} ;; -${INDENT} esac -${INDENT} done -__EOF__ - else - run_ip route show table $duplicate | while read net route; do - case $net in - default|nexthop) - ;; - *) - ensure_and_save_command " ip route add table $number $net $route" - ;; - esac - done - fi + run_ip route show table $duplicate | while read net route; do + case $net in + default|nexthop) + ;; + *) + ensure_and_save_command " ip route add table $number $net $route" + ;; + esac + done } copy_and_edit_table() { - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} ip route show table $duplicate | while read net route; do -${INDENT} case \$net in -${INDENT} default|nexthop) -${INDENT} ;; -${INDENT} *) -${INDENT} case \$(find_device \$route) in -${INDENT} `echo $copy\) | sed 's/ /|/g'` -${INDENT} run_ip route add table $number \$net \$route -${INDENT} ;; -${INDENT} esac -${INDENT} ;; -${INDENT} esac -${INDENT} done - -__EOF__ - else - run_ip route show table $duplicate | while read net route; do - case $net in - default|nexthop) - ;; - *) - if list_search $(find_device $route) $copy; then - ensure_and_save_command " ip route add table $number $net $route" - fi - ;; - esac - done - fi + run_ip route show table $duplicate | while read net route; do + case $net in + default|nexthop) + ;; + *) + if list_search $(find_device $route) $copy; then + ensure_and_save_command " ip route add table $number $net $route" + fi + ;; + esac + done } add_a_provider() { @@ -1271,68 +1211,36 @@ __EOF__ eval ${table}_number=$number - if [ $COMMAND != check ]; then - run_and_save_command " qt ip route flush table $number" + run_and_save_command " qt ip route flush table $number" - if [ "x${duplicate:=-}" != x- ]; then - if [ "x${copy:=-}" != "x-" ]; then - if [ "x${copy}" = xnone ]; then - copy=$interface - else - copy="$interface $(separate_list $copy)" - fi - copy_and_edit_table + if [ "x${duplicate:=-}" != x- ]; then + if [ "x${copy:=-}" != "x-" ]; then + if [ "x${copy}" = xnone ]; then + copy=$interface else - copy_table + copy="$interface $(separate_list $copy)" fi + copy_and_edit_table + else + copy_table fi fi if [ "x$gateway" = xdetect ] ; then - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} gateway=\$(detect_gateway $interface) - -${INDENT} if [ -n "\$gateway" ]; then -${INDENT} run_ip route replace \$gateway src \$(find_first_interface_address $interface) dev $interface table $number -${INDENT} run_ip route add default via \$gateway dev $interface table $number -${INDENT} else -${INDENT} fatal_error "Unable to detect the gateway through interface $interface" -${INDENT} fi - -__EOF__ - else - gateway=$(detect_gateway $interface) - [ -n "$gateway" ] || fatal_error "Unable to detect the gateway through interface $interface" - fi + gateway=$(detect_gateway $interface) + [ -n "$gateway" ] || fatal_error "Unable to detect the gateway through interface $interface" fi - case $COMMAND in - check|compile) - ;; - *) - ensure_and_save_command " ip route replace $gateway src $(find_first_interface_address $interface) dev $interface table $number" - ensure_and_save_command " ip route add default via $gateway dev $interface table $number" - ;; - esac + ensure_and_save_command " ip route replace $gateway src $(find_first_interface_address $interface) dev $interface table $number" + ensure_and_save_command " ip route add default via $gateway dev $interface table $number" if [ x${mark} != x- ]; then verify_mark $mark eval ${table}_mark=$mark - case $COMMAND in - check) - ;; - compile) - save_command " qt ip rule del fwmark $mark" - save_command " run_ip rule add fwmark $mark pref $((10000 + $mark)) table $number" - ;; - *) - run_and_save_command " qt ip rule del fwmark $mark" - ensure_and_save_command " ip rule add fwmark $mark pref $((10000 + $mark)) table $number" - ;; - esac + run_and_save_command " qt ip rule del fwmark $mark" + ensure_and_save_command " ip rule add fwmark $mark pref $((10000 + $mark)) table $number" fi loose= @@ -1351,19 +1259,11 @@ __EOF__ ;; balance=*) balance=yes - if [ $COMMAND = compile ]; then - save_command " DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via \$gateway dev $interface weight ${option#*=}\"" - else - DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight ${option#*=}" - fi + DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight ${option#*=}" ;; balance) balance=yes - if [ $COMMAND = compile ]; then - save_command " DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via \$gateway dev $interface weight 1\"" - else - DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight 1" - fi + DEFAULT_ROUTE="$DEFAULT_ROUTE nexthop via $gateway dev $interface weight 1" ;; loose) loose=Yes @@ -1376,44 +1276,14 @@ __EOF__ rulenum=0 - case $COMMAND in - check) - ;; - compile) - if [ -z "$loose" ]; then - cat >> $RESTOREBASE << __EOF__ - -${INDENT} rulenum=0 - -${INDENT} find_interface_addresses $interface | while read address; do -${INDENT} qt ip rule del from \$address -${INDENT} pref=\$((20000 + \$rulenum * 1000 + $number )) -${INDENT} rulenum=\$((\$rulenum + 1)) -${INDENT} run_ip rule add from \$address pref \$pref table $number -${INDENT} done - -__EOF__ - else - cat >> $RESTOREBASE << __EOF__ - -${INDENT} find_interface_addresses $interface | while read address; do -${INDENT} qt ip rule del from \$address -${INDENT} done - -__EOF__ - fi - ;; - *) - find_interface_addresses $interface | while read address; do - run_and_save_command " qt ip rule del from $address" - if [ -z "$loose" ]; then - pref=$((20000 + $rulenum * 1000 + $number )) - rulenum=$(($rulenum + 1)) - ensure_and_save_command " ip rule add from $address pref $pref table $number" - fi - done - ;; - esac + find_interface_addresses $interface | while read address; do + run_and_save_command " qt ip rule del from $address" + if [ -z "$loose" ]; then + pref=$((20000 + $rulenum * 1000 + $number )) + rulenum=$(($rulenum + 1)) + ensure_and_save_command " ip rule add from $address pref $pref table $number" + fi + done } strip_file providers $1 @@ -1422,50 +1292,25 @@ __EOF__ DEFAULT_ROUTE= balance= - if [ $COMMAND != check ]; then - progress_message2 "Processing $1..." - save_progress_message "Adding Providers..." - save_command "if [ -z \"\$NOROUTES\" ]; then" - [ $COMMAND = compile ] && save_command " DEFAULT_ROUTE=" - else - progress_message2 "Validating $1..." - fi + progress_message2 "Processing $1..." + save_progress_message "Adding Providers..." + save_command "if [ -z \"\$NOROUTES\" ]; then" 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" add_a_provider PROVIDERS="$PROVIDERS $table" - case $COMMAND in - compile) - progress_message " Provider $provider comipled" - ;; - *) - progress_message " Provider $provider Added" - ;; - esac + progress_message " Provider $provider Added" done < $TMP_DIR/providers - if [ $COMMAND != check ]; then - if [ -n "$PROVIDERS" ]; then - case $COMMAND in - compile) - if [ -n "$balance" ]; then - save_command " run_ip route replace default scope global \$DEFAULT_ROUTE" - save_command " progress_message Default route \$DEFAULT_ROUTE Added" - fi - ;; - *) - if [ -n "$DEFAULT_ROUTE" ]; then - ensure_and_save_command " ip route replace default scope global $DEFAULT_ROUTE" - progress_message " Default route $DEFAULT_ROUTE Added." - fi - ;; - esac + if [ -n "$PROVIDERS" ]; then + if [ -n "$DEFAULT_ROUTE" ]; then + ensure_and_save_command " ip route replace default scope global $DEFAULT_ROUTE" + progress_message " Default route $DEFAULT_ROUTE Added." + fi - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} cat > /etc/iproute2/rt_tables < /etc/iproute2/rt_tables < /etc/iproute2/rt_tables <> $RESTOREBASE << __EOF__ -${INDENT} \${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables -__EOF__ - done - else - cat > /etc/iproute2/rt_tables <> /etc/iproute2/rt_tables - done + for table in $PROVIDERS; do + eval number=\$${table}_number + ${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables + done - save_command " cat > /etc/iproute2/rt_tables << __EOF__" - cat /etc/iproute2/rt_tables >> $RESTOREBASE - save_command_unindented __EOF__ - fi - fi + save_command "cat > /etc/iproute2/rt_tables << __EOF__" + cat /etc/iproute2/rt_tables >> $RESTOREBASE + save_command __EOF__ - if [ $COMMAND = compile ]; then - save_command " run_ip route flush cache" - else - ensure_and_save_command " ip route flush cache" - fi - - save_command "fi" - save_command "" fi + + ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route flush cache" fi } @@ -1639,11 +1456,10 @@ validate_policy() print_policy() # $1 = source zone, $2 = destination zone { - [ $COMMAND != check ] || \ - [ $1 = $2 ] || \ - [ $1 = all ] || \ - [ $2 = all ] || \ - progress_message " Policy for $1 to $2 is $policy using chain $chain" + [ $1 = $2 ] || \ + [ $1 = all ] || \ + [ $2 = all ] || \ + progress_message " Policy for $1 to $2 is $policy using chain $chain" } ALL_POLICY_CHAINS= @@ -1770,27 +1586,13 @@ find_broadcasts() { for interface in $ALL_INTERFACES; do eval bcast=\$$(chain_base $interface)_broadcast if [ "x$bcast" = "xdetect" ]; then - if [ $COMMAND != compile ]; then - ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u - fi + 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 } -# -# Find interfaces with BROADCAST=detect -- Only returns information if we are compiling a script -# -find_bcastdetect_interfaces() { - if [ $COMMAND = compile ]; then - for interface in $ALL_INTERFACES; do - eval bcast=\$$(chain_base $interface)_broadcast - [ "x$bcast" = "xdetect" ] && echo $interface - done - fi -} - # # Find interfaces that have the passed option specified # @@ -2030,10 +1832,6 @@ stop_firewall() { case $COMMAND in stop|clear) ;; - check|compile) - kill $$ - exit 2 - ;; *) set +x @@ -2512,22 +2310,20 @@ setup_ipsec() { # set_mss() # $1 = MSS value, $2 = _in, _out or "" { - if [ $COMMAND != check ]; then - for z in $ZONES; do - case $2 in - _in) - set_mss1 ${zone}2${z} $1 - ;; - _out) - set_mss1 ${z}2${zone} $1 - ;; - *) - set_mss1 ${z}2${zone} $1 - set_mss1 ${zone}2${z} $1 - ;; - esac - done - fi + for z in $ZONES; do + case $2 in + _in) + set_mss1 ${zone}2${z} $1 + ;; + _out) + set_mss1 ${z}2${zone} $1 + ;; + *) + set_mss1 ${z}2${zone} $1 + set_mss1 ${zone}2${z} $1 + ;; + esac + done } do_options() # $1 = _in, _out or "" - $2 = option list @@ -2666,45 +2462,21 @@ setup_proxy_arp() { ;; esac - case $COMMAND in - compile) - if [ -z "$haveroute" ]; then - save_command "[ -n \"\$NOROUTES\" ] || run_ip route replace $address dev $interface" - [ -n "$persistent" ] && haveroute=yes - fi + if [ -z "$haveroute" ]; then + ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route replace $address dev $interface" + [ -n "$persistent" ] && haveroute=yes + fi - cat >> $RESTOREBASE << __EOF__ -${INDENT}if ! arp -i $external -Ds $address $external pub; then -${INDENT} fatal_error "Command \"arp -i $external -Ds $address $external pub\" failed" -${INDENT}fi + ensure_and_save_command arp -i $external -Ds $address $external pub -${INDENT}progress_message " Host $address connected to $interface added to ARP on $external" - -__EOF__ - echo $address $interface $external $haveroute >> $STATEDIR/proxyarp - ;; - check) - ;; - *) - if [ -z "$haveroute" ]; then - ensure_and_save_command "[ -n \"\$NOROUTES\" ] || ip route replace $address dev $interface" - [ -n "$persistent" ] && haveroute=yes - fi - - ensure_and_save_command arp -i $external -Ds $address $external pub - - echo $address $interface $external $haveroute >> $STATEDIR/proxyarp - ;; - esac + echo $address $interface $external $haveroute >> $STATEDIR/proxyarp progress_message " Host $address connected to $interface added to ARP on $external" } - if [ $COMMAND != check ]; then - > $STATEDIR/proxyarp + > $STATEDIR/proxyarp - save_progress_message "Setting up Proxy ARP..." - fi + save_progress_message "Setting up Proxy ARP..." while read address interface external haveroute persistent; do expandv address interface external haveroute persistent @@ -2713,27 +2485,26 @@ __EOF__ setup_one_proxy_arp done < $TMP_DIR/proxyarp - 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 + for interface in $resetlist; do + list_search $interface $setlist || \ + run_and_save_command "echo 0 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" + done - for interface in $setlist; do + for interface in $setlist; do + run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" + done + + interfaces=$(find_interfaces_by_option proxyarp) + + for interface in $interfaces; do + if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ] ; then run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" - done + progress_message " Enabled proxy ARP on $interface" + else + error_message "WARNING: Unable to enable proxy ARP on $interface" + fi + done - interfaces=$(find_interfaces_by_option proxyarp) - - for interface in $interfaces; do - if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ] ; then - run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" - progress_message " Enabled proxy ARP on $interface" - else - error_message "WARNING: Unable to enable proxy ARP on $interface" - fi - done - fi } # @@ -2886,38 +2657,20 @@ setup_mac_lists() { [ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface) - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ + blob=$(ip link show $interface 2> /dev/null) -${INDENT}blob=\$(ip link show $interface 2> /dev/null) + [ -z "$blob" ] && \ + fatal_error "Interface $interface must be up before Shorewall can start" -${INDENT}[ -z "\$blob" ] && \ -${INDENT} fatal_error "Interface $interface must be up before Shorewall can start" + ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do + address=${address%/*} + if [ -n "$broadcast" ]; then + run_iptables -t $MACLIST_TABLE -A $chain -s $address -d $broadcast -j RETURN + fi -${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do -${INDENT} address=\${address%/*} -${INDENT} if [ -n "\$broadcast" ]; then -${INDENT} run_iptables -t $MACLIST_TABLE -A $chain -s \$address -d \$broadcast -j RETURN -${INDENT} fi -${INDENT}done - -__EOF__ - else - blob=$(ip link show $interface 2> /dev/null) - - [ -z "$blob" ] && \ - fatal_error "Interface $interface must be up before Shorewall can start" - - ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do - address=${address%/*} - if [ -n "$broadcast" ]; then - run_iptables -t $MACLIST_TABLE -A $chain -s $address -d $broadcast -j RETURN - fi - - 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 - done - fi + 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 + done if [ -n "$MACLIST_LOG_LEVEL" ]; then log_rule_limit $MACLIST_LOG_LEVEL $chain $(mac_chain $interface) $MACLIST_DISPOSITION "$LOGLIMIT" "" -A -t $MACLIST_TABLE @@ -2992,10 +2745,6 @@ delete_proxy_arp() { if [ -f /var/lib/shorewall/proxyarp ]; then while read address interface external haveroute; do case $COMMAND in - compile) - save_command "qt arp -i $external -d $address pub" - [ -z "$haveroute" ] && save_command "[ -n \"\$NOROUTE\" ] || qt ip route del $address dev $interface" - ;; stop|clear) qt arp -i $external -d $address pub [ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface @@ -3022,15 +2771,6 @@ delete_proxy_arp() { [ -d $STATEDIR ] && touch $STATEDIR/proxyarp case $COMMAND in - compile) - cat >> $RESTOREBASE << __EOF__ - -${INDENT}for f in /proc/sys/net/ipv4/conf/*; do -${INDENT} [ -f \$f/proxy_arp ] && echo 0 > \$f/proxy_arp -${INDENT}done -${INDENT} -__EOF__ - ;; stop|clear) for f in /proc/sys/net/ipv4/conf/*; do [ -f $f/proxy_arp ] && echo 0 > $f/proxy_arp @@ -3081,7 +2821,7 @@ setup_nat() { add_ip_aliases= ;; *) - [ -n "$RETAIN_ALIASES" -o $COMMAND = check ] || run_and_save_command qt ip addr del $external dev $iface + [ -n "$RETAIN_ALIASES" ] || run_and_save_command qt ip addr del $external dev $iface ;; esac else @@ -3091,19 +2831,17 @@ setup_nat() { validate_one allints "ALL INTERFACES" $allints validate_one localnat "LOCAL" $localnat - 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 - - [ -n "$localnat" ] && \ - run_iptables2 -t nat -A OUTPUT -d $external $policyout -j DNAT --to-destination $internal + 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 + [ -n "$localnat" ] && \ + run_iptables2 -t nat -A OUTPUT -d $external $policyout -j DNAT --to-destination $internal + if [ -n "$add_ip_aliases" ]; then list_search $external $ALIASES_TO_ADD || \ ALIASES_TO_ADD="$ALIASES_TO_ADD $external $interface" @@ -3112,14 +2850,14 @@ setup_nat() { # # At this point, we're just interested in the network translation # - [ $COMMAND = check ] || > $STATEDIR/nat + > $STATEDIR/nat if [ -n "$POLICY_MATCH" ]; then policyin="-m policy --pol none --dir in" policyout="-m policy --pol none --dir out" fi - [ -n "$RETAIN_ALIASES" -o $COMMAND = check ] || save_progress_message "Setting up one-to-one NAT..." + [ -n "$RETAIN_ALIASES" ] || save_progress_message "Setting up one-to-one NAT..." while read external interface internal allints localnat; do expandv external interface internal allints localnat @@ -3137,31 +2875,15 @@ delete_nat() { run_iptables -t nat -F run_iptables -t nat -X - if [ $COMMAND = compile ]; then - [ -d $STATEDIR ] && touch $STATEDIR/nat + if [ -f /var/lib/shorewall/nat ]; then + while read external interface; do + qt ip addr del $external dev $interface + done < /var/lib/shorewall/nat - cat >> $RESTOREBASE << __EOF__ - -${INDENT}if [ -f /var/lib/shorewall/nat ]; then -${INDENT} while read external interface; do -${INDENT} qt ip addr del \$external dev \$interface -${INDENT} done < /var/lib/shorewall/nat -${INDENT} -${INDENT} rm -f {/var/lib/shorewall}/nat -${INDENT}fi - -__EOF__ - else - if [ -f /var/lib/shorewall/nat ]; then - while read external interface; do - qt ip addr del $external dev $interface - done < /var/lib/shorewall/nat - - rm -f {/var/lib/shorewall}/nat - fi - - [ -d $STATEDIR ] && touch $STATEDIR/nat + rm -f {/var/lib/shorewall}/nat fi + + [ -d $STATEDIR ] && touch $STATEDIR/nat } # @@ -3282,13 +3004,7 @@ setup_traffic_shaping() ensure_and_save_tc() { run_tc $@ - - if [ $COMMAND != compile ]; then - # - # compile_command()'s version of run_tc does the save - # - save_command tc $@ - fi + save_command tc $@ } rate_to_kbit() { @@ -3481,45 +3197,30 @@ setup_traffic_shaping() validate_tcdevices_file validate_tcclasses_file - if [ $COMMAND != check ]; then - if [ -s $TMP_DIR/tcdevices ]; then - save_progress_message "Setting up Traffic Control..." - progress_message2 "Processing $devfile..." + if [ -s $TMP_DIR/tcdevices ]; then + save_progress_message "Setting up Traffic Control..." + progress_message2 "Processing $devfile..." - while read device inband outband defmark ackmark; do - expandv device inband outband defmark ackmark - tcdev="$device $inband $outband" - add_root_tc - case $COMMAND in - compile) - progress_message " TC Device $tcdev Compiled." - ;; - *) - progress_message " TC Device $tcdev Added." - ;; - esac - done < $TMP_DIR/tcdevices - fi - - if [ -s $TMP_DIR/tcclasses ]; then - progress_message2 "Processing $classfile..." - - 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 - case $COMMAND in - compile) - progress_message " TC Class $tcdev Compiled." - ;; - *) - progress_message " TC Class \"$tcdev\" Added." - ;; - esac - done < $TMP_DIR/tcclasses - fi + 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 + + if [ -s $TMP_DIR/tcclasses ]; then + progress_message2 "Processing $classfile..." + + 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 + } # @@ -3796,14 +3497,7 @@ process_tc_rule() done done - case $COMMAND in - compile) - progress_message " TC Rule \"$rule\" compiled" - ;; - *) - progress_message " TC Rule \"$rule\" added" - ;; - esac + progress_message " TC Rule \"$rule\" added" } # @@ -3879,31 +3573,16 @@ delete_tc() run_user_exit tcclear - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT}ip link list | while read inx interface details; do -${INDENT} case \$inx in -${INDENT} [0-9]*) -${INDENT} qt tc qdisc del dev \${interface%:} root -${INDENT} qt tc qdisc del dev \${interface%:} ingress -${INDENT} ;; -${INDENT} *) -${INDENT} ;; -${INDENT} esac -${INDENT}done -__EOF__ - else - run_ip link list | \ - while read inx interface details; do - case $inx in - [0-9]*) - clear_one_tc ${interface%:} - ;; - *) - ;; - esac - done - fi + run_ip link list | \ + while read inx interface details; do + case $inx in + [0-9]*) + clear_one_tc ${interface%:} + ;; + *) + ;; + esac + done } # @@ -4103,15 +3782,7 @@ process_accounting_rule() { if do_iptables -A $chain $(fix_bang $rule) ; then [ -n "$rule2" ] && run_iptables2 -A $jumpchain $rule2 - case $COMMAND in - compile) - progress_message " Accounting rule" $action $chain $source $dest $proto $port $sport $user Compiled - save_progress_message_short " Accounting rule $action $chain $source $dest $proto $port $sport $user Added" - ;; - *) - progress_message " Accounting rule" $action $chain $source $dest $proto $port $sport $user Added - ;; - esac + progress_message " Accounting rule" $action $chain $source $dest $proto $port $sport $user Added else accounting_error fi @@ -4125,8 +3796,6 @@ setup_accounting() # $1 = Name of accounting file progress_message2 "Setting up Accounting..." - [ $COMMAND = compile ] && save_progress_message "Setting up Accounting..." - strip_file accounting $1 while read action chain source dest proto port sport user ; do @@ -4142,108 +3811,6 @@ setup_accounting() # $1 = Name of accounting file } -# -# Check the configuration -# -check_config() { - - disclaimer() { - echo - 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" - echo - } - - report_capabilities - - echo "Verifying Configuration..." - - verify_os_version - - 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= - - if [ -n "$MACLIST_TTL" -a -z "$RECENT_MATCH" ]; then - startup_error "MACLIST_TTL requires the Recent Match capability which is not present in your Kernel and/or iptables" - fi - - progress_message2 "Determining Zones..." - - determine_zones - - if [ $QUIET -lt 2 ]; then - display_list "IPv4_Zones:" $IPV4_ZONES - [ -n "$IPSEC_ZONES" ] && \ - display_list "IPSEC Zones:" $IPSEC_ZONES - display_list "Firewall Zone:" $FW - fi - - setup_ipsec - - progress_message2 "Validating interfaces file..." - - validate_interfaces_file - - progress_message2 "Validating hosts file..." - - validate_hosts_file - - progress_message2 "Determining Hosts in Zones..." - - determine_interfaces - determine_hosts - - progress_message2 "Validating policy file..." - - validate_policy - - setup_providers $(find_file providers) - - validate_blacklist - - progress_message2 "Validating Proxy ARP" - strip_file proxyarp - setup_proxy_arp - - progress_message2 "Validating NAT..." - strip_file nat - setup_nat - - progress_message2 "Pre-validating Actions..." - - process_actions1 - - progress_message2 "Validating rules file..." - - rules=$(find_file rules) - strip_file rules $rules - process_rules - - progress_message2 "Validating Actions..." - - process_actions2 - process_actions3 - - masq=$(find_file masq) - [ -f $masq ] && setup_masq $masq - - setup_traffic_shaping - - rm -rf $TMP_DIR - [ -n "$RESTOREBASE" ] && rm -f $RESTOREBASE - - echo "Configuration Validated" - - disclaimer - -} - # # Refresh queuing and classes # @@ -4289,8 +3856,7 @@ refresh_tc() { # Add one Filter Rule from an action -- Helper function for the action file processor # # The caller has established the following variables: -# COMMAND = current command. If 'check', we're executing a 'check' -# which only goes through the motions. +# COMMAND = current command. # client = SOURCE IP or MAC # server = DESTINATION IP or interface # protocol = Protocol @@ -4463,37 +4029,35 @@ add_an_action() ;; esac - if [ $COMMAND != check ]; then - if [ -n "${excludesource}${excludedest}" ]; then - handle_exclusion - fi + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi - if [ -n "${serv}" ]; then - for serv1 in $(separate_list $serv); do - for srv in $(firewall_ip_range $serv1); do - if [ -n "$loglevel" ]; then - log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ - $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) - fi + if [ -n "${serv}" ]; then + for serv1 in $(separate_list $serv); do + for srv in $(firewall_ip_range $serv1); do + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ + $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) + fi - run_iptables2 -A $chain1 $proto $multiport $cli $sports \ - $(dest_ip_range $srv) $dports $ratelimit $user -j $target - done + run_iptables2 -A $chain1 $proto $multiport $cli $sports \ + $(dest_ip_range $srv) $dports $ratelimit $user -j $target done - else - if [ -n "$loglevel" ]; then - log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ - $(fix_bang $proto $sports $multiport $cli $dest_interface $dports) - fi - - run_iptables2 -A $chain1 $proto $multiport $cli $dest_interface $sports \ - $dports $ratelimit $user -j $target + done + else + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain1 $action $logtarget "$ratelimit" "$logtag" -A $user \ + $(fix_bang $proto $sports $multiport $cli $dest_interface $dports) fi + + run_iptables2 -A $chain1 $proto $multiport $cli $dest_interface $sports \ + $dports $ratelimit $user -j $target fi } # -# Process a record from an action file for the 'start', 'restart' or 'check' commands +# Process a record from an action file for the 'start', or 'restart' commands # process_action() # $1 = chain (Chain to add the rules to) # $2 = action (The action name for logging purposes) @@ -4719,18 +4283,7 @@ process_action() # $1 = chain (Chain to add the rules to) # # Report Result # - case $COMMAND in - check) - progress_message " Rule \"$rule\" checked." - ;; - compile) - progress_message " Rule \"$rule\" compiled." - save_progress_message_short " Rule \"$rule\" added." - ;; - *) - progress_message " Rule \"$rule\" added." - ;; - esac + progress_message " Rule \"$rule\" added." } # @@ -4767,30 +4320,27 @@ createlogactionchain() # $1 = Action Name, $2 = Log Level [: Log Tag ] ;; esac - [ "$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 + while havechain %${CHAIN}${actchain}; do + actchain=$(($actchain + 1)) + [ $actchain -eq 10 -a ${#CHAIN} -eq 28 ] && CHAIN=$(echo $CHAIN | truncate 27) # %...nn makes 30 + done CHAIN=%${CHAIN}${actchain} eval ${action}_actchain=$(($actchain + 1)) - if [ $COMMAND != check ]; then - createchain $CHAIN No - LEVEL=${level%:*} - if [ "$LEVEL" != "$level" ]; then - TAG=${level#*:} - else - TAG= - fi - - [ none = "${LEVEL%\!}" ] && LEVEL= - - run_user_exit $1 + createchain $CHAIN No + LEVEL=${level%:*} + if [ "$LEVEL" != "$level" ]; then + TAG=${level#*:} + else + TAG= fi + [ none = "${LEVEL%\!}" ] && LEVEL= + + run_user_exit $1 + eval ${action}_chains=\"\$${action}_chains $level $CHAIN\" } @@ -4815,12 +4365,11 @@ createactionchain() # $1 = Action, including log level and tag if any ;; *) CHAIN=$1 - if [ $COMMAND != check ]; then - LEVEL= - TAG= - createchain $CHAIN no - run_user_exit $CHAIN - fi + + LEVEL= + TAG= + createchain $CHAIN no + run_user_exit $CHAIN ;; esac } @@ -4838,9 +4387,8 @@ find_logactionchain() # $1 = Action, including log level and tag if any level=${fullaction#*:} ;; *) - if [ $COMMAND != check ]; then - havechain $action || fatal_error "Fatal error in find_logactionchain" - fi + + havechain $action || fatal_error "Fatal error in find_logactionchain" echo $action return @@ -5221,169 +4769,105 @@ process_actions3() { xlevel=$2 xtag=$3 - [ $COMMAND = compile ] && save_progress_message "Creating action chain $xaction1" - # # Handle Builtin actions # case $xaction1 in dropBcast) - if [ "$COMMAND" != check ]; then - if [ -n "$USEPKTTYPE" ]; then + if [ -n "$USEPKTTYPE" ]; then + 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 + + run_iptables -A dropBcast -m pkttype --pkt-type broadcast -j DROP + run_iptables -A dropBcast -m pkttype --pkt-type multicast -j DROP + else + for address in $(find_broadcasts) 255.255.255.255 224.0.0.0/4 ; do case $xlevel in - none'!') - ;; + 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 + [ -n "$xlevel" ] && \ + log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -d $address ;; esac - run_iptables -A dropBcast -m pkttype --pkt-type broadcast -j DROP - run_iptables -A dropBcast -m pkttype --pkt-type multicast -j DROP - else - for interface in $(find_bcastdetect_interfaces); do - cat >> $RESTOREBASE << __EOF__ - -${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do -__EOF__ - case $xlevel in - none*) - ;; - *) - [ -n "$xlevel" ] && \ - cat >> $RESTOREBASE << __EOF__ -${INDENT} log_rule_limit ${xlevel%\!} $xchain dropBcast DROP "" "$xtag" -A -d \$address -__EOF__ - ;; - esac - - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -A $xchain -d \$address -j DROP -${INDENT}done - -__EOF__ - done - - 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 - - run_iptables -A $xchain -d $address -j DROP - done - fi + run_iptables -A $xchain -d $address -j DROP + done fi ;; allowBcast) - if [ "$COMMAND" != check ]; then - if [ -n "$USEPKTTYPE" ]; then + if [ -n "$USEPKTTYPE" ]; then + 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 + + 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'!') - ;; + 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 + [ -n "$xlevel" ] && \ + log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -d $address ;; esac - run_iptables -A allowBcast -m pkttype --pkt-type broadcast -j ACCEPT - run_iptables -A allowBcast -m pkttype --pkt-type multicast -j ACCEPT - else - for interface in $(find_bcastdetect_interfaces); do - cat >> $RESTOREBASE << __EOF__ - -${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do -__EOF__ - case $xlevel in - none*) - ;; - *) - [ -n "$xlevel" ] && \ - cat >> $RESTOREBASE << __EOF__ -${INDENT} log_rule_limit ${xlevel%\!} $xchain allowBcast ACCEPT "" "$xtag" -A -d \$address -__EOF__ - ;; - esac - - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -A $xchain -d \$address -j -${INDENT}done - -__EOF__ - done - - 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 - - run_iptables -A $xchain -d $address -j ACCEPT - done - fi + run_iptables -A $xchain -d $address -j ACCEPT + done fi ;; dropNotSyn) - 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 + [ -n "$xlevel" ] && \ + log_rule_limit ${xlevel%\!} $xchain dropNotSyn DROP "" "$xtag" -A -p tcp ! --syn + run_iptables -A $xchain -p tcp ! --syn -j DROP ;; rejNotSyn) - 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 + [ -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 ;; 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 + [ -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 ;; 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 + [ -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 ;; forwardUPnP) ;; 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 + 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 ;; 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 + [ -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 ;; *) # @@ -5545,25 +5029,10 @@ add_nat_rule() { eval interfaces=\$${source}_interfaces if [ -n "$DETECT_DNAT_IPADDRS" -a "$source" != "$FW" ]; then - - if [ $COMMAND = compile ]; then - save_command "" - if [ $(list_count1 $interfaces) -eq 1 ]; then - save_command "addr=\$(find_first_interface_address $interface)" - else - savecomment "addr=" - for interface in $interfaces; do - cat >> $RESTOREBASE << __EOF__ -${INDENT}addr="\$addr \$(find_first_interface_address $interface)" -__EOF__ - done - fi - else - addr= - for interface in $interfaces; do - addr=${addr:+$addr,}$(find_first_interface_address $interface) - done - fi + addr= + for interface in $interfaces; do + addr=${addr:+$addr,}$(find_first_interface_address $interface) + done fi ;; !*) @@ -5602,93 +5071,60 @@ __EOF__ # Generate nat table rules - if [ $COMMAND != check ]; then - if [ "$source" = "$FW" ]; then - if [ -n "${excludesource}${excludedests}" ]; then - build_exclusion_chain chain nat "$excludesource" $excludedests + if [ "$source" = "$FW" ]; then + if [ -n "${excludesource}${excludedests}" ]; then + build_exclusion_chain chain nat "$excludesource" $excludedests - for adr in $(separate_list $addr); do - run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain - done + for adr in $(separate_list $addr); do + run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain + done - if [ -n "$loglevel" ]; then - log_rule_limit $loglevel $chain OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat - fi - - addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection - else - for adr in $(separate_list $addr); do - if [ -n "$loglevel" ]; then - log_rule_limit $loglevel OUTPUT OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat \ - $(fix_bang $proto $cli $sports $userandgroup $(dest_ip_range $adr) $multiport $dports) - fi - - run_iptables2 -t nat -A OUTPUT $ratelimit $proto $sports $userandgroup $(dest_ip_range $adr) $multiport $dports -j $target1 - done + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat fi + + addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection else - if [ -n "${excludesource}${excludedests}${excludezones}" ]; then - build_exclusion_chain chain nat "$excludesource" $excludedests - - if [ $addr = detect ]; then - ensurenatchain $(dnat_chain $source) - - cat >> $RESTOREBASE << __EOF__ - -${INDENT}for adr in \$addr; do -${INDENT} run_iptables -t nat -A $(fix_bang $(dnat_chain $source) $cli $proto $multiport $sports $dports) -d \$adr -j $chain -__EOF__ - else - for adr in $(separate_list $addr); do - addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain - done - fi - - 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 - + for adr in $(separate_list $addr); do if [ -n "$loglevel" ]; then - log_rule_limit $loglevel $chain $(dnat_chain $source) $logtarget "$ratelimit" "$logtag" -A -t nat + log_rule_limit $loglevel OUTPUT OUTPUT $logtarget "$ratelimit" "$logtag" -A -t nat \ + $(fix_bang $proto $cli $sports $userandgroup $(dest_ip_range $adr) $multiport $dports) fi - addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection - else - chain=$(dnat_chain $source) - - if [ $addr = detect ]; then - ensurenatchain $chain - - cat >> $RESTOREBASE << __EOF__ - -${INDENT}for adr in \$addr; do -__EOF__ - if [ -n "$loglevel" ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat $(fix_bang $proto $cli $sports $multiport $dports) -d \$adr -__EOF__ - fi - - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -t nat -A $chain $(fix_bang $proto $ratelimit $cli $sports $multiport $dports) -d \$adr -j $target1 -__EOF__ - else - for adr in $(separate_list $addr); do - if [ -n "$loglevel" ]; then - ensurenatchain $chain - log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat \ - $(fix_bang $proto $cli $sports $(dest_ip_range $adr) $multiport $dports) - fi - - addnatrule $chain $proto $ratelimit $cli $sports \ - -d $adr $multiport $dports -j $target1 - done - fi - fi + run_iptables2 -t nat -A OUTPUT $ratelimit $proto $sports $userandgroup $(dest_ip_range $adr) $multiport $dports -j $target1 + done fi + elif [ -n "${excludesource}${excludedests}${excludezones}" ]; then + build_exclusion_chain chain nat "$excludesource" $excludedests + + for adr in $(separate_list $addr); do + addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain + done + + 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 + + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $(dnat_chain $source) $logtarget "$ratelimit" "$logtag" -A -t nat + fi + + addnatrule $chain $ratelimit $proto -j $target1 # Protocol is necessary for port redirection + else + chain=$(dnat_chain $source) + for adr in $(separate_list $addr); do + if [ -n "$loglevel" ]; then + ensurenatchain $chain + log_rule_limit $loglevel $chain $chain $logtarget "$ratelimit" "$logtag" -A -t nat \ + $(fix_bang $proto $cli $sports $(dest_ip_range $adr) $multiport $dports) + fi + + addnatrule $chain $proto $ratelimit $cli $sports \ + -d $adr $multiport $dports -j $target1 + done fi # Replace destination port by the new destination port @@ -5706,7 +5142,7 @@ __EOF__ } # -# Process a record from the rules file for the 'start', 'restart' or 'check' commands +# Process a record from the rules file for the 'start' or 'restart' commands # process_rule() # $1 = target # $2 = clients @@ -5734,8 +5170,7 @@ process_rule() # $1 = target # 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. + # COMMAND = current command. # client = SOURCE IP or MAC # server = DESTINATION IP or interface # protocol = Protocol @@ -5966,122 +5401,110 @@ process_rule() # $1 = target esac if [ -n "${serv}${servport}" ]; then - if [ $COMMAND != check ]; then - # A specific server or server port given + # A specific server or server port given - 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 + 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 - if [ -n "${excludesource}${excludedest}" ]; then - handle_exclusion - fi + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi - 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 - if [ "$addr" = detect ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -A $chain $state $proto $ratelimit $multiport $cli $sports $(dest_ip_range $srv) $dports -m conntrack --ctorigdst \$adr $user -j $target -${INDENT}done - -__EOF__ - else - 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 \ - $user $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) $state - fi - - run_iptables2 -A $chain $state $proto $ratelimit $multiport $cli $sports \ - $(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $user -j $target - done - fi - else + 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 $user \ - $state $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A -m conntrack --ctorigdst $adr \ + $user $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) $state fi - if [ -n "$nonat" ]; then - addnatrule $(dnat_chain $source) $proto $multiport \ - $cli $sports $(dest_ip_range $srv) $dports $ratelimit $user -j RETURN - fi - - if [ "$logtarget" != NONAT ]; then - run_iptables2 -A $chain $state $proto $multiport $cli $sports \ - $(dest_ip_range $srv) $dports $ratelimit $user -j $target - fi + run_iptables2 -A $chain $state $proto $ratelimit $multiport $cli $sports \ + $(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $user -j $target + done + else + if [ -n "$loglevel" -a -z "$natrule" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports) fi - done + + if [ -n "$nonat" ]; then + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $(dest_ip_range $srv) $dports $ratelimit $user -j RETURN + fi + + if [ "$logtarget" != NONAT ]; then + run_iptables2 -A $chain $state $proto $multiport $cli $sports \ + $(dest_ip_range $srv) $dports $ratelimit $user -j $target + fi + fi done - else - if [ -n "$loglevel" -a -z "$natrule" ]; then - log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ - $state $(fix_bang $proto $sports $multiport $cli $dports) - fi - - [ -n "$nonat" ] && \ - addnatrule $(dnat_chain $source) $proto $multiport \ - $cli $sports $dports $ratelimit $user -j RETURN - - [ "$logtarget" != NONAT ] && \ - run_iptables2 -A $chain $state $proto $multiport $cli $sports \ - $dports $ratelimit $user -j $target + done + else + if [ -n "$loglevel" -a -z "$natrule" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $sports $multiport $cli $dports) fi + + [ -n "$nonat" ] && \ + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $dports $ratelimit $user -j RETURN + + [ "$logtarget" != NONAT ] && \ + run_iptables2 -A $chain $state $proto $multiport $cli $sports \ + $dports $ratelimit $user -j $target fi fi else # Destination is a simple zone - if [ $COMMAND != check ]; then - if [ -n "${excludesource}${excludedest}" ]; then - handle_exclusion - fi + if [ -n "${excludesource}${excludedest}" ]; then + handle_exclusion + fi - if [ -n "$addr" ]; then - for adr in $(separate_list $addr); do - if [ -n "$loglevel" ]; then - log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ - $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr) - fi - - if [ "$logtarget" != LOG ]; then - if [ -n "$nonat" ]; then - addnatrule $(dnat_chain $source) $proto $multiport \ - $cli $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j RETURN - fi - - if [ "$logtarget" != NONAT ]; then - run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \ - $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j $target - fi - fi - done - else + if [ -n "$addr" ]; then + for adr in $(separate_list $addr); do if [ -n "$loglevel" ]; then log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ - $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports) + $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr) fi if [ "$logtarget" != LOG ]; then if [ -n "$nonat" ]; then addnatrule $(dnat_chain $source) $proto $multiport \ - $cli $sports $dports $ratelimit $user -j RETURN + $cli $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j RETURN fi if [ "$logtarget" != NONAT ]; then run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \ - $sports $dports $ratelimit $user -j $target + $sports $dports $ratelimit $user -m conntrack --ctorigdst $adr -j $target fi fi + done + else + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $user \ + $state $(fix_bang $proto $multiport $cli $dest_interface $sports $dports) + fi + + if [ "$logtarget" != LOG ]; then + if [ -n "$nonat" ]; then + addnatrule $(dnat_chain $source) $proto $multiport \ + $cli $sports $dports $ratelimit $user -j RETURN + fi + + if [ "$logtarget" != NONAT ]; then + run_iptables2 -A $chain $state $proto $multiport $cli $dest_interface \ + $sports $dports $ratelimit $user -j $target + fi fi fi fi @@ -6359,7 +5782,7 @@ __EOF__ [ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all} - [ $COMMAND = check ] || ensurechain $chain + ensurechain $chain # Generate Netfilter rule(s) @@ -6485,18 +5908,7 @@ __EOF__ # # Report Result # - case $COMMAND in - check) - progress_message " Rule \"$rule\" checked." - ;; - compile) - progress_message " Rule \"$rule\" compiled." - save_progress_message_short " Rule \"$rule\" added." - ;; - *) - progress_message " Rule \"$rule\" added." - ;; - esac + progress_message " Rule \"$rule\" added." } # @@ -6597,7 +6009,7 @@ process_macro() # $1 = target } # -# Process the rules file for the 'start', 'restart' or 'check' command. +# Process the rules file for the 'start' or 'restart' command. # process_rules() { @@ -6933,14 +6345,7 @@ process_tos_rule() { esac done - case $COMMAND in - compile) - progress_message " Rule \"$rule\" compiled." - ;; - *) - progress_message " Rule \"$rule\" added." - ;; - esac + progress_message " Rule \"$rule\" added." } # @@ -7303,20 +6708,13 @@ setup_masq() source="${networks:=0.0.0.0/0}" - detectinterface= - case $source in *.*.*|+*|!+*) ;; *) - if [ $COMMAND = compile ]; then - detectinterface=$networks - networks= - else - networks=$(get_routed_networks $networks) - [ -z "$networks" ] && fatal_error "Unable to determine the routes through interface \"$source\"" - networks="$networks" - fi + networks=$(get_routed_networks $networks) + [ -z "$networks" ] && fatal_error "Unable to determine the routes through interface \"$source\"" + networks="$networks" ;; esac @@ -7397,37 +6795,20 @@ setup_masq() [ -z "$pre_nat" ] && chain=$(masq_chain $interface) || chain=$(snat_chain $interface) - [ $COMMAND = compile ] && ensurenatchain $chain - case $destnets in !*) destnets=${destnets#!} - if [ $COMMAND != check ]; then - build_exclusion_chain newchain nat "$nomasq" "$destnets" - if [ -n "$networks" ]; then - for s in $networks; do - addnatrule $chain $(source_ip_range $s) $proto $ports $policy -j $newchain - done - networks= - elif [ -n "$detectinterface" ]; then - cat >> $RESTOREBASE << __EOF__ + build_exclusion_chain newchain nat "$nomasq" "$destnets" -${INDENT}networks="\$(get_routed_networks $detectinterface)" - -${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" - -${INDENT}for network in \$networks; do -${INDENT} run_iptables -t nat -A $chain -s \$network $proto $ports $policy -j $newchain -${INDENT}done - -__EOF__ - else - addnatrule $chain -j $newchain - fi - else + 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 chain=$newchain @@ -7440,38 +6821,18 @@ __EOF__ ;; *) if [ -n "$nomasq" ]; then - if [ $COMMAND != check ]; then - build_exclusion_chain newchain nat $nomasq + build_exclusion_chain newchain nat $nomasq - 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 - elif [ -n "$detectinterface" ]; then - cat >> $RESTOREBASE << __EOF__ - -${INDENT}networks="\$(get_routed_networks $detectinterface)" - -${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" - -${INDENT}for network in \$networks; do -__EOF__ + if [ -n "$networks" ]; then + for s in $networks; do for destnet in $(separate_list $destnets); do - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -t nat -A $chain -s \$network $(dest_ip_range $destnet) $proto $sports $policy -j $netchain -__EOF__ + addnatrule $chain $(both_ip_ranges $s $destnet) $proto $ports $policy -j $newchain done - cat >> $RESTOREBASE << __EOF__ - -${INDENT}done -__EOF__ - else - for destnet in $(separate_list $destnets); do - addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $newchain - done - fi + done + else + for destnet in $(separate_list $destnets); do + addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $newchain + done fi chain=$newchain @@ -7522,11 +6883,9 @@ __EOF__ if [ -n "$networks" ]; then for network in $networks; do - 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 + for destnet in $(separate_list $destnets); do + addnatrule $chain $(both_ip_ranges $network $destnet) $proto $ports $policy -j $target $addrlist + done if [ -n "$addresses" ]; then progress_message " To $destination $displayproto from $network through ${interface} using $addresses" @@ -7534,39 +6893,10 @@ __EOF__ progress_message " To $destination $displayproto from $network through ${interface}" fi done - elif [ -n "$detectinterface" ]; then - cat >> $RESTOREBASE << __EOF__ - -${INDENT}networks="\$(get_routed_networks $detectinterface)" - -${INDENT}[ -z "\$networks" ] && fatal_error "Unable to determine the routes through interface \"$detectinterface\"" - -${INDENT}for network in \$networks; do -__EOF__ - for destnet in $(separate_list $destnets); do - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -t nat -A $chain -s \$network $(dest_ip_range $destnet) $proto $ports $policy -j $target $addrlist -__EOF__ - done - - if [ -n "$addresses" ]; then - message=" To $destination $displayproto from \$network through ${interface} using $addresses" - else - message=" To $destination $displayproto from \$network through ${interface}" - fi - - cat >> $RESTOREBASE << __EOF__ -${INDENT} progress_message "$message" -${INDENT}done - -__EOF__ - else - 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 + for destnet in $(separate_list $destnets); do + addnatrule $chain $(dest_ip_range $destnet) $proto $ports $policy -j $target $addrlist + done if [ -n "$addresses" ]; then progress_message " To $destination $displayproto from $source through ${interface} using $addresses" @@ -7581,7 +6911,7 @@ __EOF__ if [ -n "$NAT_ENABLED" ]; then progress_message2 "Masqueraded Networks and Hosts:" - [ $COMMAND = check ] || save_progress_message "Setting up Masquerading/SNAT..." + save_progress_message "Setting up Masquerading/SNAT..." fi while read fullinterface networks addresses proto ports ipsec; do @@ -7602,13 +6932,11 @@ __EOF__ # $dport = destination port selector # add_blacklist_rule() { - if [ "$COMMAND" != check ]; then - if [ -n "$BLACKLIST_LOGLEVEL" ]; then - log_rule $BLACKLIST_LOGLEVEL blacklst $BLACKLIST_DISPOSITION $(fix_bang $source $proto $dport) - fi - - run_iptables2 -A blacklst $source $proto $dport -j $disposition + if [ -n "$BLACKLIST_LOGLEVEL" ]; then + log_rule $BLACKLIST_LOGLEVEL blacklst $BLACKLIST_DISPOSITION $(fix_bang $source $proto $dport) fi + + run_iptables2 -A blacklst $source $proto $dport -j $disposition } # @@ -7687,11 +7015,7 @@ process_blacklist_rec() { addr="$addr $protocol" fi - if [ "$COMMAND" = check ]; then - progress_message " $addr" Verified - else - progress_message " $addr added to Black List" - fi + progress_message " $addr added to Black List" done } @@ -7926,8 +7250,6 @@ initialize_netfilter () { progress_message2 "Deleting user chains..." - [ $COMMAND = compile ] && save_progress_message "Deleting user chains..." - exists_INPUT=Yes exists_OUTPUT=Yes exists_FORWARD=Yes @@ -7992,8 +7314,6 @@ initialize_netfilter () { run_and_save_command disable_ipv6 fi - [ $COMMAND = compile ] && save_progress_message "Enabling Loopback and DNS Lookups" - # # Enable the Loopback interface for now # @@ -8019,8 +7339,6 @@ initialize_netfilter () { if [ -f /var/lib/shorewall/save ]; then progress_message2 "Setting up dynamic rules..." - [ $COMMAND = compile ] && save_progress_message "Restoring dynamic rules..." - if [ -f /var/lib/shorewall/save ]; then while read target ignore1 ignore2 address rest; do case $target in @@ -8038,8 +7356,6 @@ initialize_netfilter () { progress_message2 "Creating Interface Chains..." - [ $COMMAND = compile ] && save_progress_message "Creating Interface Chains..." - for interface in $ALL_INTERFACES; do createchain $(forward_chain $interface) no run_iptables -A $(forward_chain $interface) $state -j dynamic @@ -8056,16 +7372,6 @@ add_common_rules() { local broadcasts="$(find_broadcasts) 255.255.255.255 224.0.0.0/4" drop_broadcasts() { - for interface in $(find_bcastdetect_interfaces); do - cat >> $RESTOREBASE << __EOF__ - -${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do -${INDENT} run_iptables -A reject -d \$address -j DROP -${INDENT}done - -__EOF__ - done - for address in $broadcasts ; do run_iptables -A reject -d $address -j DROP done @@ -8073,24 +7379,6 @@ __EOF__ # # Populate the smurf chain # - [ $COMMAND = compile ] && save_progress_message "Setting up SMURF control..." - - for interface in $(find_bcastdetect_interfaces); do - cat >> $RESTOREBASE << __EOF__ - -${INDENT}ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u | while read address; do -__EOF__ - [ -n "$SMURF_LOG_LEVEL" ] && \ - cat >> $RESTOREBASE << __EOF__ -${INDENT} log_rule $SMURF_LOG_LEVEL smurfs DROP -s \$address -__EOF__ - cat >> $RESTOREBASE << __EOF__ -${INDENT} run_iptables -A smurfs -s \$address -j DROP -${INDENT}done - -__EOF__ - done - for address in $broadcasts ; do [ -n "$SMURF_LOG_LEVEL" ] && log_rule $SMURF_LOG_LEVEL smurfs DROP -s $address run_iptables -A smurfs $(source_ip_range $address) -j DROP @@ -8136,8 +7424,6 @@ __EOF__ # # Process Black List # - [ $COMMAND = compile ] && save_progress_message "Setting up Black List..." - setup_blacklist # @@ -8149,8 +7435,6 @@ __EOF__ progress_message2 "Adding Anti-smurf Rules" - [ $COMMAND = compile ] && save_progress_message "Adding Anti-smurf Jumps..." - for host in $hosts; do ipsec=${host%^*} host=${host#*^} @@ -8172,8 +7456,6 @@ __EOF__ progress_message2 "Adding rules for DHCP" - [ $COMMAND = compile ] && save_progress_message "Setting up rules for DHCP..." - for interface in $interfaces; do if [ -n "$BRIDGING" ]; then is_bridge=$( brctl show $interface 2> /dev/null | grep ^$interface[[:space:]] ) @@ -8192,8 +7474,6 @@ __EOF__ if [ -n "$hosts" ]; then progress_message2 "Enabling RFC1918 Filtering" - [ $COMMAND = compile ] && save_progress_message "Setting up RFC1918 Filtering..." - strip_file rfc1918 createchain norfc1918 no @@ -8285,8 +7565,6 @@ __EOF__ if [ -n "$hosts" ]; then progress_message2 "Setting up TCP Flags checking..." - [ $COMMAND = compile ] && save_progress_message "Setting up TCP Flags checking..." - createchain tcpflags no if [ -n "$TCP_FLAGS_LOG_LEVEL" ]; then @@ -8342,20 +7620,10 @@ __EOF__ # save_progress_message "Setting up ARP filtering..." - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT}for f in /proc/sys/net/ipv4/conf/*; do -${INDENT} [ -f \$f/arp_filter ] && echo 0 > \$f/arp_filter -${INDENT} [ -f \$f/arp_ignore ] && echo 0 > \$f/arp_ignore -${INDENT}done - -__EOF__ - else - for f in /proc/sys/net/ipv4/conf/*; do - run_and_save_command "[ -f $f/arp_filter ] && echo 0 > $f/arp_filter" - run_and_save_command "[ -f $f/arp_ignore ] && echo 0 > $f/arp_ignore" - done - fi + for f in /proc/sys/net/ipv4/conf/*; do + run_and_save_command "[ -f $f/arp_filter ] && echo 0 > $f/arp_filter" + run_and_save_command "[ -f $f/arp_ignore ] && echo 0 > $f/arp_ignore" + done interfaces=$(find_interfaces_by_option arp_filter) interfaces1=$(find_interfaces_by_option1 arp_ignore) @@ -8363,51 +7631,26 @@ __EOF__ if [ -n "${interfaces}${interfaces1}" ]; then progress_message2 "Setting up ARP Filtering..." - if [ $COMMAND = compile ]; then - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/arp_filter - cat >> $RESTOREBASE << __EOF__ -${INDENT}if [ -f $file ]; then -${INDENT} echo 1 > $file -${INDENT}else -${INDENT} error_message "WARNING: Cannot set ARP filtering on $interface" -${INDENT}fi -__EOF__ - done + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/arp_filter + if [ -f $file ]; then + run_and_save_command "echo 1 > $file" + else + error_message \ + "WARNING: Cannot set ARP filtering on $interface" + fi + done - for interface in $interfaces1; do - file=/proc/sys/net/ipv4/conf/$interface/arp_ignore - eval value="\$$(chain_base $interface)_arp_ignore" - cat >> $RESTOREBASE << __EOF__ -${INDENT}if [ -f $file ]; then -${INDENT} echo $value > $file -${INDENT}else -${INDENT} error_message "WARNING: Cannot set ARP filtering on $interface" -${INDENT}fi -__EOF__ - done - else - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/arp_filter - if [ -f $file ]; then - run_and_save_command "echo 1 > $file" - else - error_message \ - "WARNING: Cannot set ARP filtering on $interface" - fi - done - - 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" - fi - done - fi + 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" + fi + done fi # # Route Filtering @@ -8419,40 +7662,19 @@ __EOF__ save_progress_message "Setting up Route Filtering..." - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ + for f in /proc/sys/net/ipv4/conf/*; do + run_and_save_command "[ -f $f/rp_filter ] && echo 0 > $f/rp_filter" + done -${INDENT}for f in /proc/sys/net/ipv4/conf/*; do -${INDENT} [ -f \$f/log_martians ] && echo 0 > \$f/rp_filter -${INDENT}done - -__EOF__ - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/rp_filter - - cat >> $RESTOREBASE << __EOF__ -${INDENT}if [ -f $file ]; then -${INDENT} echo 1 > $file -${INDENT}else -${INDENT} error_message "WARNING: Cannot set route filtering on $interface" -${INDENT}fi -__EOF__ - done - else - for f in /proc/sys/net/ipv4/conf/*; do - run_and_save_command "[ -f $f/rp_filter ] && echo 0 > $f/rp_filter" - done - - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/rp_filter - if [ -f $file ]; then - run_and_save_command "echo 1 > $file" - else - error_message \ - "WARNING: Cannot set route filtering on $interface" - fi - done - fi + for interface in $interfaces; do + file=/proc/sys/net/ipv4/conf/$interface/rp_filter + if [ -f $file ]; then + run_and_save_command "echo 1 > $file" + else + error_message \ + "WARNING: Cannot set route filtering on $interface" + fi + done run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter" @@ -8474,40 +7696,19 @@ __EOF__ save_progress_message "Setting up Martian Logging..." - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ + for f in /proc/sys/net/ipv4/conf/*; do + run_and_save_command "[ -f $f/log_martians ] && echo 0 > $f/log_martians" + done -${INDENT}for f in /proc/sys/net/ipv4/conf/*; do -${INDENT} [ -f \$f/log_martians ] && echo 0 > \$f/log_martians -${INDENT}done - -__EOF__ - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/log_martians - - cat >> $RESTOREBASE << __EOF__ -${INDENT}if [ -f $file ]; then -${INDENT} echo 1 > $file -${INDENT}else -${INDENT} error_message "WARNING: Cannot set Martian logging on $interface" -${INDENT}fi -__EOF__ - done - else - 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 \ - "WARNING: Cannot set Martian logging on $interface" - fi - done - fi + 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 \ + "WARNING: Cannot set Martian logging on $interface" + fi + done if [ -n "$LOG_MARTIANS" ]; then run_and_save_command "echo 1 > /proc/sys/net/ipv4/conf/default/log_martians" @@ -8521,18 +7722,9 @@ __EOF__ # save_progress_message "Setting up Accept Source Routing..." - if [ $COMMAND = compile ]; then - cat >> $RESTOREBASE << __EOF__ -${INDENT}for f in /proc/sys/net/ipv4/conf/*; do -${INDENT} [ -f \$f/accept_source_route ] && echo 0 > \$f/accept_source_route -${INDENT}done - -__EOF__ - else - 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 - fi + 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) @@ -8541,29 +7733,15 @@ __EOF__ save_progress_message "Setting up Source Routing..." - if [ $COMMAND = compile ]; then - for interface in $interfaces; do - file=/proc/sys/net/ipv4/conf/$interface/accept_source_route - - cat >> $RESTOREBASE << __EOF__ -${INDENT}if [ -f $file ]; then -${INDENT} echo 1 > $file -${INDENT}else -${INDENT} error_message "WARNING: Cannot set Accept Source Routing on $interface" -${INDENT}fi -__EOF__ - done - else - 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 \ - "WARNING: Cannot set Accept Source Routing on $interface" - fi - done - fi + 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 \ + "WARNING: Cannot set Accept Source Routing on $interface" + fi + done fi if [ -n "$DYNAMIC_ZONES" ]; then @@ -8590,8 +7768,6 @@ __EOF__ if [ -n "$interfaces" ]; then progress_message2 "Setting up UPnP..." - [ $COMMAND = compile ] && save_progress_message "Setting up UPnP..." - createnatchain UPnP for interface in $interfaces; do @@ -9089,646 +8265,6 @@ define_firewall() # $1 = Command (Start or Restart) mv -f $RESTOREBASE /var/lib/shorewall/restore-tail } -# -# Compile a script that will stop the firewall -# -# This function is called by compile_firewall() so all of the overloaded functions -# from that script are available here -# -compile_stop_firewall() { - local IPTABLES_COMMAND="\$IPTABLES" - local INDENT=" " - - cat >> $RESTOREBASE << __EOF__ - -stop_firewall() { - - deletechain() { - qt \$IPTABLES -L \$1 -n && qt \$IPTABLES -F \$1 && qt \$IPTABLES -X \$1 - } - - deleteallchains() { - \$IPTABLES -F - \$IPTABLES -X - } - - setcontinue() { - \$IPTABLES -A \$1 -m state --state ESTABLISHED,RELATED -j ACCEPT - } - - case \$COMMAND in - stop|clear) - ;; - *) - set +x - - [ -n "\${RESTOREFILE:=restore}" ] - - RESTOREPATH=/var/lib/shorewall/\$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; 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 - - determine_capabilities - - 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 - - if [ -f /var/lib/shorewall/proxyarp ]; then - while read address interface external haveroute; do - qt arp -i \$external -d \$address pub - [ -z "\${haveroute}\${NOROUTES}" ] && qt ip route del \$address dev \$interface - done < /var/lib/shorewall/proxyarp - fi - - for f in /proc/sys/net/ipv4/conf/*; do - [ -f \$f/proxy_arp ] && echo 0 > \$f/proxy_arp - done - -__EOF__ - [ -n "$CLEAR_TC" ] && save_command "delete_tc1" - - [ -n "$DISABLE_IPV6" ] && save_command "disable_ipv6" - - process_criticalhosts - - if [ -n "$CRITICALHOSTS" ]; then - if [ -z "$ADMINISABSENTMINDED" ]; then - cat >> $RESTOREBASE << __EOF__ - - for chain in INPUT OUTPUT; do - setpolicy \$chain ACCEPT - done - - setpolicy FORWARD DROP - - deleteallchains - - 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 chain in INPUT OUTPUT; do - setpolicy $\chain DROP - done - -__EOF__ - else - cat >> $RESTOREBASE << __EOF__ - - for chain in INPUT OUTPUT; do - setpolicy \$chain ACCEPT - done - - setpolicy FORWARD DROP - - deleteallchains - - 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 - - setpolicy INPUT DROP - - for chain in INPUT FORWARD; do - setcontinue \$chain - done - -__EOF__ - fi - elif [ -z "$ADMINISABSENTMINDED" ]; then - cat >> $RESTOREBASE << __EOF__ - - for chain in INPUT OUTPUT FORWARD; do - setpolicy \$chain DROP - done - - deleteallchains - -__EOF__ - else - cat >> $RESTOREBASE << __EOF__ - - for chain in INPUT FORWARD; do - setpolicy \$chain DROP - done - - setpolicy OUTPUT ACCEPT - - deleteallchains - - for chain in INPUT FORWARD; do - setcontinue \$chain - done - -__EOF__ - fi - - process_routestopped -A - - save_command "\$IPTABLES -A INPUT -i lo -j ACCEPT" - - [ -z "$ADMINISABSENTMINDED" ] && \ - save_command "\$IPTABLES -A OUTPUT -o lo -j ACCEPT" - - for interface in $(find_interfaces_by_option dhcp); do - save_command "\$IPTABLES -A INPUT -p udp -i $interface --dport 67:68 -j ACCEPT" - [ -z "$ADMINISABSENTMINDED" ] && \ - save_command "\$IPTABLES -A OUTPUT -p udp -o $interface --dport 67:68 -j ACCEPT" - # - # This might be a bridge - # - save_command "\$IPTABLES -A FORWARD -p udp -i $interface -o $interface --dport 67:68 -j ACCEPT" - done - - save_command - - case "$IP_FORWARDING" in - [Oo][Nn]) - save_command "echo 1 > /proc/sys/net/ipv4/ip_forward" - save_command "progress_message2 IP Forwarding Enabled" - ;; - [Oo][Ff][Ff]) - save_command "echo 0 > /proc/sys/net/ipv4/ip_forward" - save_command "progress_message2 IP Forwarding Disabled!" - ;; - esac - - cat >> $RESTOREBASE << __EOF__ - - run_user_exit stopped - - set_state "Stopped" - - logger "Shorewall Stopped" - - 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 - # - kill \$\$ - ;; - esac -} -__EOF__ -} - -# -# Compile a Restore Script -# -compile_firewall() # $1 = File Name -{ - local IPTABLES_COMMAND=run_iptables - local INDENT="" - - outfile=$1 dir=$(dirname $1) - # - # We overload a number of functions when compiling. - # - ensure_and_save_command() - { - echo "${INDENT}${@} >> $RESTOREBASE" - } - - run_and_save_command() - { - echo "${INDENT}${@}" >> $RESTOREBASE - } - - do_iptables() { - save_command \$IPTABLES $@ - } - - qt_iptables() { - # - # 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 - - save_command qt \$IPTABLES $@ - } - - createchain2() # $1 = chain name, $2 = If "yes", create default rules - { - local c=$(chain_base $1) - - ensurechain $1 - - if [ $2 = yes ]; then - case $SECTION in - NEW|DONE) - finish_chain_section $1 ESTABLISHED,RELATED - ;; - RELATED) - finish_chain_section $1 ESTABLISHED - ;; - esac - - fi - - eval exists_${c}=Yes - } - - run_iptables() { - # - # 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 - - save_command "$IPTABLES_COMMAND $@" - - } - - run_iptables2() { - save_command run_iptables $(fix_bang $@) - } - - run_ip() { - if ! ip $@ ; then - error_message "ERROR: Command \"ip $@\" Failed" - rm -rf $TMP_DIR - exit 2 - fi - } - - run_tc() { - save_command run_tc $@ - } - - deletechain() # $1 = name of chain - { - save_command "qt \$IPTABLES -L $1 -n && qt \$IPTABLES -F $1 && qt \$IPTABLES -X $1" - } - - fix_bang() { - echo $@ | sed 's/!/! /g' - } - # - # END OVERLOADED FUNCTIONS - # - - verify_os_version - verify_ip - - [ -d /var/lib/shorewall ] || { mkdir -p /var/lib/shorewall ; chmod 700 /var/lib/shorewall; } - - [ -d $dir ] || startup_error "Directory $dir does not exist" - [ -h $dir ] && startup_error "$dir is a Symbolic Link" - [ -d $outfile ] && startup_error "$outfile is a Directory" - [ -h $outfile ] && startup_error "$outfile is a Symbolic Link" - [ -f $outfile -a ! -x $outfile ] && startup_error "$outfile exists and is not a restore file" - - RESTOREBASE=$(mktempfile /tmp) - - STATEDIR=$(mktempdir) - - TMP_DIR1=$STATEDIR - - [ -n "$RESTOREBASE" ] || startup_error "Cannot create temporary file in /tmp" - - [ -z "$PROGRAM" ] && save_command "#! $SHOREWALL_SHELL --" - - cat >> $RESTOREBASE << __EOF__ -# -# Compiled startup file generated by Shorewall $VERSION - $(date)" -# -__EOF__ - - if [ -n "$EXPORT" ]; then - cat /usr/share/shorewall/functions >> $RESTOREBASE - else - cat >> $RESTOREBASE << __EOF__ - -. /usr/share/shorewall/functions -__EOF__ - - fi - - compile_stop_firewall - -cat >> $RESTOREBASE << __EOF__ - -setpolicy() { - \$IPTABLES -P \$1 \$2 -} - -clear_firewall() { - stop_firewall - - setpolicy INPUT ACCEPT - setpolicy FORWARD ACCEPT - setpolicy OUTPUT ACCEPT - - run_iptables -F - - echo 1 > /proc/sys/net/ipv4/ip_forward - -__EOF__ - if [ -n "$DISABLE_IPV6" ]; then - cat >> $RESTOREBASE << __EOF__ - if 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 - -__EOF__ - fi - - cat >> $RESTOREBASE << __EOF__ - run_user_exit clear - - set_state "Cleared" - - logger "Shorewall Cleared" -} - -fatal_error() -{ - echo " ERROR: \$@" >&2 - stop_firewall - exit 2 -} - -run_iptables() -{ - if ! \$IPTABLES \$@; then - error_message "ERROR: Command \"\$IPTABLES \$@\" Failed" - stop_firewall - exit 2 - fi -} - -run_ip() -{ - if ! ip \$@; then - error_message "ERROR: Command \"ip \$@\" Failed" - stop_firewall - exit 2 - fi -} - -run_tc() { - if ! tc \$@ ; then - error_message "ERROR: Command \"tc \$@\" Failed" - stop_firewall - exit 2 - fi -} - -initialize() { -__EOF__ - if [ -z "$EXPORT" ]; then - cat >> $RESTOREBASE << __EOF__ - if [ ! -f /usr/share/shorewall/version ] || [ \$(cat /usr/share/shorewall/version) != $VERSION ]; then - error_message "ERROR: This script requires Shorewall version $VERSION" - exit 2 - fi - -__EOF__ - fi - - cat >> $RESTOREBASE << __EOF__ - # - # These variables are required by the library functions called in this script - # - [ -n \${COMMAND:=restart} ] - [ -n \${QUIET:=0} ] - MODULESDIR="$MODULESDIR" - MODULE_SUFFIX="$MODULE_SUFFIX" - LOGLIMIT="$LOGLIMIT" - LOGTAGONLY="$LOGTAGONLY" - LOGRULENUMBERS="$LOGRULENUMBERS" - LOGFORMAT="$LOGFORMAT" - RESTOREFILE="$RESTOREFILE" - VERSION="$VERSION" - CONFIG_PATH="$CONFIG_PATH" - -__EOF__ - if [ -n "$IPTABLES" ]; then - cat >> $RESTOREBASE << __EOF__ - IPTABLES="$IPTABLES" - - [ -e "$IPTABLES" ] || startup_error "\$IPTABLES=$IPTABLES does not exist or is not executable" -__EOF__ - else - cat >> $RESTOREBASE << __EOF__ - IPTABLES=\$(mywhich iptables 2> /dev/null) - - [ -z "\$IPTABLES" ] && startup_error "Can't find iptables executable" -__EOF__ - fi - - cat >> $RESTOREBASE << __EOF__ - - STOPPING= - # - # The library requires that /var/lib/shorewall exist - # - [ -d /var/lib/shorewall ] || mkdir -p /var/lib/shorewall -} - -__EOF__ - save_command "define_firewall() {" - INDENT=" " - -cat >> $RESTOREBASE << __EOF__ - - load_kernel_modules - -__EOF__ - - progress_message2 "Initializing..." - save_progress_message_short "Initializing..." - - initialize_netfilter - - progress_message2 "Compiling Proxy ARP"; setup_proxy_arp - # - # [re]-Establish routing - # - setup_providers $(find_file providers) - [ -n "$ROUTEMARK_INTERFACES" ] && setup_routes - - progress_message2 "Compiling NAT..."; setup_nat - progress_message2 "Compiling NETMAP..."; setup_netmap - progress_message2 "Compiling Common Rules"; add_common_rules - - save_progress_message "Setting up SYN Flood Protection..." - - setup_syn_flood_chains - - save_progress_message "Setting up IPSEC management..." - - setup_ipsec - - maclist_hosts=$(find_hosts_by_option maclist) - - if [ -n "$maclist_hosts" ]; then - save_progress_message "Setting up MAC Filtration..." - setup_mac_lists - fi - - progress_message2 "Compiling $(find_file rules)..." - save_progress_message "Setting up Rules..." - process_rules - - tunnels=$(find_file tunnels) - if [ -f $tunnels ]; then - progress_message2 "Compiling $tunnels..." - save_progress_message "Setting up Tunnels..." - setup_tunnels $tunnels - fi - - save_progress_message "Setting up Actions..." - - progress_message2 "Compiling Actions..."; process_actions2 - process_actions3 - - save_progress_message "Applying Policies..." - - progress_message2 "Compiling $(find_file policy)..."; apply_policy_rules - - masq=$(find_file masq) - if [ -f $masq ]; then - setup_masq $masq - fi - - tos=$(find_file tos) - if [ -f $tos -a -n "$MANGLE_ENABLED" ]; then - save_progress_message "Setting up TOS..." - process_tos $tos - fi - - ecn=$(find_file ecn) - if [ -f $ecn -a -n "$MANGLE_ENABLED" ]; then - save_progress_message "Setting up ECN..." - setup_ecn $ecn - fi - - if [ -n "$MANGLE_ENABLED" ]; then - save_progress_message "Setting up TC Rules..." - setup_tc - fi - - progress_message2 "Compiling Rule Activation..." - save_progress_message "Activating Rules..." - activate_rules - - if [ -n "$ALIASES_TO_ADD" ]; then - save_command add_ip_aliases $ALIASES_TO_ADD - fi - - for file in chains nat proxyarp zones; do - append_file $file - done - - save_command "date > /var/lib/shorewall/restarted" - - run_user_exit start - - [ -n "$DELAYBLACKLISTLOAD" ] && refresh_blacklist - - createchain shorewall no - - save_command set_state "Started" - - run_user_exit started - - INDENT= - save_command "}" - save_command "" - - if [ -n "$PROGRAM" ]; then - cat $(find_file prog.header) $RESTOREBASE $(find_file prog.footer) > $outfile - rm $RESTOREBASE - else - save_command "initialize" - save_command "define_firewall" - mv -f $RESTOREBASE $outfile - fi - - chmod 700 $outfile - - echo "Shorewall configuration compiled to $outfile" - - rm -rf $TMP_DIR - rm -rf $TMP_DIR1 - -} - # # Refresh the firewall # @@ -10530,7 +9066,7 @@ do_initialize() { # Give Usage Information # usage() { - echo "Usage: $0 [debug] {start|stop|reset|restart|refresh|clear|{generate|compile} }" + echo "Usage: $0 [debug] {start|stop|reset|restart|refresh|clear}" exit 1 } @@ -10639,19 +9175,6 @@ case "$COMMAND" in my_mutex_off ;; - check) - [ $# -ne 1 ] && usage - do_initialize - check_config - ;; - - compile|generate) - [ $# -ne 2 ] && usage - do_initialize - COMMAND=compile - compile_firewall $2 - ;; - add) [ $# -lt 3 ] && usage do_initialize diff --git a/Shorewall/shorewall b/Shorewall/shorewall index 7530dc55b..d22d8072f 100755 --- a/Shorewall/shorewall +++ b/Shorewall/shorewall @@ -790,7 +790,7 @@ check_command() { export NOROUTES - exec $SHOREWALL_SHELL $FIREWALL $debugging $nolock check + exec $SHOREWALL_SHELL /usr/share/shorewall/compiler $debugging $nolock check } # # Reload Command Executor