mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-30 19:43:45 +01:00
52fc432522
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@4692 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
863 lines
21 KiB
Bash
863 lines
21 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Shorewall 3.3 -- /usr/share/shorewall/lib.actions
|
|
#
|
|
# 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)
|
|
#
|
|
# 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
|
|
#
|
|
# This library is loaded by /usr/share/shorewall/compiler when USE_ACTIONS=Yes
|
|
# (either explicitly specified or defaulted).
|
|
#
|
|
|
|
#
|
|
# Function to create/find appropriate action chain -- callable in user scripts
|
|
# that want to invoke an action.
|
|
#
|
|
get_actionchain() # $1 = Action from a rule, including log level and tag if any
|
|
{
|
|
if list_search ${1%%:*} $ACTIONS; then
|
|
if ! list_search $1 $USEDACTIONS; then
|
|
createactionchain $1
|
|
USEDACTIONS="$USEDACTIONS $1"
|
|
fi
|
|
|
|
echo $(find_logactionchain $1)
|
|
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
|
|
;;
|
|
tcp:syn)
|
|
proto="$proto --syn"
|
|
do_ports
|
|
;;
|
|
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."
|
|
}
|
|
|
|
#
|
|
# 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
|
|
}
|
|
|
|
#
|
|
# The next three functions implement the three phases of action processing.
|
|
#
|
|
# The first phase (process_actions1) occurs before the rules file is processed. ${SHAREDIR}/actions.std
|
|
# and ${CONFDIR}/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 <action>, the variable 'requiredby_<action>' lists the
|
|
# action[:level[:tag]] of each action invoked by <action>.
|
|
# d) All actions are listed in the global variable ACTIONS.
|
|
# e) Common actions are recorded (in variables of the name <policy>_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 <action>
|
|
# is merged onto this list, its action chain is created. Where logging is specified, a chain with the name
|
|
# %<action>n is used where the <action> name is truncated on the right where necessary to ensure that the total
|
|
# length of the chain name does not exceed 30 characters.
|
|
#
|
|
# 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() {
|
|
|
|
strip_file actions
|
|
|
|
strip_file actions.std ${SHAREDIR}/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
|
|
*:*)
|
|
error_message "WARNING: Default Actions are now specified in /etc/shorewall/shorewall.conf"
|
|
xaction=${xaction%:*}
|
|
;;
|
|
esac
|
|
|
|
[ -z "$xaction" ] && continue
|
|
|
|
[ "$xaction" = "$(chain_base $xaction)" ] || fatal_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)
|
|
;;
|
|
COMMENT)
|
|
;;
|
|
*)
|
|
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"
|
|
fatal_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"
|
|
fatal_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"
|
|
fatal_error "Invalid TARGET in rule \"$rule\""
|
|
fi
|
|
fi
|
|
fi
|
|
;;
|
|
|
|
esac
|
|
done < $TMP_DIR/$f
|
|
else
|
|
fatal_error "Missing Action File: $f"
|
|
fi
|
|
|
|
ACTIONS="$ACTIONS $xaction"
|
|
fi
|
|
done < $TMP_DIR/$inputfile
|
|
done
|
|
|
|
for action in $DROP_DEFAULT $REJECT_DEFAULT; do
|
|
case $action in
|
|
none)
|
|
;;
|
|
*)
|
|
if list_search $action $ACTIONS; then
|
|
list_search $action $USEDACTIONS || USEDACTIONS="$USEDACTIONS $action"
|
|
fi
|
|
;;
|
|
esac
|
|
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)"
|
|
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() is in the compiler. What follows is called from that function when the action
|
|
# being processed is not a builtin.
|
|
|
|
process_action3() {
|
|
|
|
local f=action.$xaction1 comment=
|
|
|
|
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
|
|
#
|
|
;;
|
|
COMMENT)
|
|
if [ -n "$COMMENTS" ]; then
|
|
comment=$(echo $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec)
|
|
save_command COMMENT=\"$comment\"
|
|
else
|
|
error_message "COMMENT ignored -- requires comment support in iptables/Netfilter"
|
|
fi
|
|
continue
|
|
;;
|
|
*)
|
|
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
|
|
-|SOURCE)
|
|
mclients=${xclients}
|
|
;;
|
|
DEST)
|
|
mclients=${xservers}
|
|
;;
|
|
*)
|
|
mclients=$(merge_macro_source_dest $mclients $xclients)
|
|
;;
|
|
esac
|
|
else
|
|
mclients=${xclients}
|
|
fi
|
|
|
|
if [ -n "$mservers" ]; then
|
|
case $mservers in
|
|
-|DEST)
|
|
mservers=${xservers}
|
|
;;
|
|
SOURCE)
|
|
mservers=${xclients}
|
|
;;
|
|
*)
|
|
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
|
|
|
|
[ -n "$COMMENTS" ] && save_command COMMENT=
|
|
|
|
}
|