shorewall_code/Shorewall-shell/lib.providers

495 lines
13 KiB
Bash

#!/bin/sh
#
# Shorewall 4.1 -- /usr/share/shorewall/lib.providers
#
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
#
# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
local number
local mark
local duplicate
local interface
local gateway
local options
local provider
local address
local copy
local route
local loose
local addresses
local rulenum
local rulebase
local balance
local save_indent
save_indent="$INDENT"
local mask
mask=
local first
first=Yes
local save_indent1
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
local n
local iface
local option
local optional
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
[ -n "$DELETE_THEN_ADD" ] && qt ip rule del fwmark $mark
indent >&3 << __EOF__
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
__EOF__
[ -n "$DELETE_THEN_ADD" ] && save_command " qt ip rule del from \$address"
indent >&3 << __EOF__
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__
elif [ -n "$DELETE_THEN_ADD" ]; then
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
local 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 "${dest:=to 0.0.0.0/0}" ]
if [ -n "$source" ]; then
case $source in
*:*)
source="iif ${source%:*} from ${source#*:}"
;;
*.*.*)
source="from $source"
;;
*)
source="iif $source"
;;
esac
else
source='from 0.0.0.0/0'
fi
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"
[ -n "$DELETE_THEN_ADD" ] && 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
save_command "if [ -w /etc/iproute2/rt_tables ]; then"
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
save_command "fi"
save_command
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
mask=0xFF
local save_indent
save_indent="$INDENT"
[ -n "$HIGH_ROUTE_MARKS" ] && mask=0xFF00
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 --set-mark $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
}