shorewall_code/Shorewall-shell/lib.providers
2007-07-22 13:44:06 +00:00

448 lines
12 KiB
Bash

#!/bin/sh
#
# Shorewall 4.0 -- /usr/share/shorewall/lib.providers
#
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
#
# (c) 1999,2000,2001,2002,2003,2004,2005,2006,2007 - 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 the providers file is
# non-empty.
#
#
# Process the providers file
#
setup_providers()
{
local table number mark duplicate interface gateway options provider address copy route loose addresses rulenum rulebase balance save_indent="$INDENT" mask= first=Yes save_indent1=
copy_table() {
indent >&3 << __EOF__
ip route show table $duplicate | while read net route; do
case \$net in
default|nexthop)
;;
*)
run_ip route add table $number \$net \$route
;;
esac
done
__EOF__
}
copy_and_edit_table() {
indent >&3 << __EOF__
ip route show table $duplicate | while read net route; do
case \$net in
default|nexthop)
;;
*)
case \$(find_device \$route) in
`echo $copy\) | sed 's/ /|/g'`
run_ip route add table $number \$net \$route
;;
esac
;;
esac
done
__EOF__
}
balance_default_route() # $1 = weight
{
balance=yes
save_command
if [ -n "$first" ]; then
if [ -n "$gateway" ] ; then
save_command "DEFAULT_ROUTE=\"nexthop via $gateway dev $interface weight $1\""
else
save_command "DEFAULT_ROUTE=\"nexthop dev $interface weight $1\""
fi
first=
else
if [ -n "$gateway" ] ; then
save_command "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via $gateway dev $interface weight $1\""
else
save_command "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop dev $interface weight $1\""
fi
fi
}
add_a_provider() {
local t n iface option optional=
[ -n "$MANGLE_ENABLED" ] || fatal_error "Providers require mangle support in your kernel and iptables"
for t in $PROVIDERS local main default unspec; do
if [ "$t" = "$table" ]; then
fatal_error "Duplicate Provider: $table, provider: \"$provider\""
fi
eval n=\$${t}_number
#
# The following is because the %$#@ shell doesn't accept hex numbers in '-eq' tests
#
if [ $(($n)) -eq $(($number)) ]; then
fatal_error "Duplicate Provider number: $number, provider: \"$provider\""
fi
done
eval ${table}_number=$number
indent >&3 << __EOF__
#
# Add Provider $table ($number)
#
__EOF__
save_command "if interface_is_usable $interface; then"
save_indent1="$INDENT"
INDENT="$INDENT "
iface=$(chain_base $interface)
save_command "${iface}_up=Yes"
save_command "qt ip route flush table $number"
indent >&3 << __EOF__
echo "qt ip route flush table $number" >> \${VARDIR}/undo_routing
__EOF__
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
elif [ "x${copy:=-}" != x- ]; then
fatal_error "A non-empty COPY column requires that a routing table be specified in the DUPLICATE column"
fi
if [ "x$gateway" = xdetect ] ; then
gateway='$gateway'
indent >&3 << __EOF__
gateway=\$(detect_gateway $interface)
if [ -n "\$gateway" ]; then
run_ip route replace \$gateway src \$(find_first_interface_address $interface) dev $interface table $number
run_ip route add default via \$gateway dev $interface table $number
else
fatal_error "Unable to detect the gateway through interface $interface"
fi
__EOF__
elif [ "x$gateway" != "x-" -a -n "$gateway" ]; then
indent >&3 << __EOF__
run_ip route replace $gateway src \$(find_first_interface_address $interface) dev $interface table $number
run_ip route add default via $gateway dev $interface table $number
__EOF__
else
gateway=
save_command "run_ip route add default dev $interface table $number"
fi
if [ x${mark} != x- ]; then
verify_mark $mark
if [ $(($mark)) -lt 256 ]; then
if [ -n "$HIGH_ROUTE_MARKS" ]; then
fatal_error "Invalid Mark Value ($mark) with HIGH_ROUTE_MARKS=Yes"
fi
elif [ -z "$HIGH_ROUTE_MARKS" ]; then
fatal_error "Invalid Mark Value ($mark) with HIGH_ROUTE_MARKS=No"
fi
eval ${table}_mark=$mark
indent >&3 << __EOF__
qt ip rule del fwmark $mark
run_ip rule add fwmark $mark pref $((10000 + $mark)) table $number
echo "qt ip rule del fwmark $mark" >> \${VARDIR}/undo_routing
__EOF__
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"
[ 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_default_route ${option#*=}
;;
balance)
balance_default_route 1
;;
loose)
loose=Yes
;;
optional)
optional=Yes
;;
*)
error_message "WARNING: Invalid option ($option) ignored in provider \"$provider\""
;;
esac
done
rulenum=0
if [ -z "$loose" ]; then
rulebase=$(( 20000 + ( 256 * ($number-1) ) ))
indent >&3 << __EOF__
rulenum=0
find_interface_addresses $interface | while read address; do
qt ip rule del from \$address
run_ip rule add from \$address pref \$(( $rulebase + \$rulenum )) table $number
echo "qt ip rule del from \$address" >> \${VARDIR}/undo_routing
rulenum=\$((\$rulenum + 1))
done
__EOF__
else
indent >&3 << __EOF__
find_interface_addresses $interface | while read address; do
qt ip rule del from \$address
done
__EOF__
[ -n "$balance" ] && error_message "WARNING: 'balance' and 'loose' should not be specified together - Provider \"$provider\""
fi
indent >&3 << __EOF__
progress_message " Provider $table ($number) Added"
__EOF__
INDENT="$save_indent1"
save_command else
if [ -n "$optional" ]; then
save_command " error_message \"WARNING: Interface $interface is not configured -- Provider $table ($number) not Added\""
save_command " ${iface}_up="
else
save_command " fatal_error \"ERROR: Interface $interface is not configured -- Provider $table ($number) Cannot be Added\""
fi
save_command fi
save_command
}
verify_provider()
{
local p n
for p in $PROVIDERS main; do
[ "$p" = "$1" ] && return 0
eval n=\$${p}_number}
[ "$n" = "$1" ] && return 0
done
fatal_error "Unknown provider $1 in route rule \"$rule\""
}
add_an_rtrule()
{
verify_provider $provider
[ "x$source" = x- ] && source=
[ "x$dest" = x- ] && dest= || dest="to $dest"
[ -n "${source}${dest}" ] || fatal_error "You must specify either the source or destination in an rt rule: \"$rule\""
[ -n "$source" ] && case $source in
*:*)
source="iif ${source%:*} from ${source#*:}"
;;
*.*.*)
source="from $source"
;;
*)
source="iif $source"
;;
esac
case "$priority" in
[0-9][0-9][0-9][0-9]|[0-9][0-9][0-9][0-9][0-9])
;;
*)
fatal_error "Invalid priority ($priority) in rule \"$rule\""
;;
esac
priority="priority $priority"
save_command "qt ip rule del $source $dest $priority"
save_command "run_ip rule add $source $dest $priority table $provider"
indent >&3 << __EOF__
echo "qt ip rule del $source $dest $priority" >> \${VARDIR}/undo_routing
__EOF__
progress_message "Routing rule \"$rule\" $DONE"
}
#
# E x e c u t i o n B e g i n s H e r e
#
local_number=255
main_number=254
default_number=253
unspec_number=0
balance=
progress_message2 "$DOING $1..."
save_command
save_command "if [ -z \"\$NOROUTES\" ]; then"
INDENT="$INDENT "
indent >&3 << __EOF__
#
# Undo any changes made since the last time that we [re]started -- this will not restore the default route
#
undo_routing
#
# Save current routing table database so that it can be restored later
#
cp /etc/iproute2/rt_tables \${VARDIR}/
#
# Capture the default route(s) if we don't have it (them) already.
#
[ -f \${VARDIR}/default_route ] || ip route list | grep -E '^\s*(default |nexthop )' > \${VARDIR}/default_route
#
# Initialize the file that holds 'undo' commands
#
> \${VARDIR}/undo_routing
__EOF__
save_progress_message "Adding Providers..."
save_command "DEFAULT_ROUTE="
while read table number mark duplicate interface gateway options copy; do
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 "if [ -n \"\$DEFAULT_ROUTE\" ]; then"
save_command " run_ip route replace default scope global \$DEFAULT_ROUTE"
save_command " progress_message \"Default route '\$(echo \$DEFAULT_ROUTE | sed 's/\$\\s*//')' Added\""
save_command "else"
save_command " error_message \"WARNING: No Default route added (all 'balance' providers are down)\""
save_command " restore_default_route"
save_command "fi"
save_command
else
save_command "#"
save_command "# We don't have any 'balance' providers so we retore any default route that we've saved"
save_command "#"
save_command restore_default_route
fi
cat >&3 << __EOF__
${INDENT}cat > /etc/iproute2/rt_tables <<EOF
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
EOF
${INDENT}echocommand=\$(find_echo)
__EOF__
for table in $PROVIDERS; do
eval number=\$${table}_number
indent >&3 << __EOF__
\$echocommand "$number\t$table" >> /etc/iproute2/rt_tables
__EOF__
done
if [ -s $TMP_DIR/route_rules ]; then
progress_message2 "$DOING $(find_file route_rules)..."
save_command
while read source dest provider priority; do
rule="$source $dest $priority $provider"
add_an_rtrule
done < $TMP_DIR/route_rules
fi
fi
save_command
save_command "run_ip route flush cache"
INDENT="$save_indent"
save_command "fi"
save_command
}
#
# Set up Route marking (Only called if $ROUTEMARK_INTERFACES is non-empty)
#
setup_route_marking()
{
local mask=0xFF mark_op="--set-mark" save_indent="$INDENT"
[ -n "$HIGH_ROUTE_MARKS" ] && mask=0xFF00 && mark_op="--or-mark"
run_iptables -t mangle -A PREROUTING -m connmark ! --mark 0/$mask -j CONNMARK --restore-mark --mask $mask
run_iptables -t mangle -A OUTPUT -m connmark ! --mark 0/$mask -j CONNMARK --restore-mark --mask $mask
createmanglechain routemark
for interface in $ROUTEMARK_INTERFACES ; do
iface=$(chain_base $interface)
eval mark_value=\$${iface}_routemark
save_command
save_command "if [ -n \"\$${iface}_up\" ]; then"
INDENT="$INDENT "
run_iptables -t mangle -A PREROUTING -i $interface -m mark --mark 0/$mask -j routemark
run_iptables -t mangle -A routemark -i $interface -j MARK $mark_op $mark_value
INDENT="$save_indent"
save_command "fi"
done
save_command
run_iptables -t mangle -A routemark -m mark ! --mark 0/$mask -j CONNMARK --save-mark --mask $mask
}