forked from extern/shorewall_code
b7c130b10b
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@7812 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
463 lines
12 KiB
Bash
463 lines
12 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 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
|
|
|
|
[ -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 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=0xFF 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
|
|
|
|
}
|