Add support for explicit routing rules

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@3763 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2006-04-02 15:17:41 +00:00
parent 64cdda4888
commit f39537bc90
5 changed files with 154 additions and 29 deletions

View File

@ -2,6 +2,8 @@ Changes in 3.2.0 Beta 4
1) Fix 'routeback' with bridge ports. 1) Fix 'routeback' with bridge ports.
2) Add support for explicit routing rules.
Changes in 3.2.0 Beta 3 Changes in 3.2.0 Beta 3
1) Correct handling of verbosity in the 'try' command. 1) Correct handling of verbosity in the 'try' command.

View File

@ -693,14 +693,14 @@ get_set_flags() # $1 = set name and optional [levels], $2 = src or dst
{ {
# #
# Note: There is a lot of unnecessary evaluation in this function just so my text # Note: There is a lot of unnecessary evaluation in this function just so my text
# editor doesn't get lost trying to follow the shell syntax for highlighting. # editor (kate) doesn't get lost trying to follow the shell syntax for highlighting.
# #
local temp setname=$1 options=$2 firstcase='*\[[1-6]\]' secondcase='*\[*\]' local temp setname=$1 options=$2
[ -n "$IPSET_MATCH" ] || fatal_error "Your kernel and/or iptables does not include ipset match: $1" [ -n "$IPSET_MATCH" ] || fatal_error "Your kernel and/or iptables does not include ipset match: $1"
case $1 in case $1 in
$firstcase) *\[[1-6]\])
eval temp='${1#*\[}' eval temp='${1#*\[}'
eval temp='${temp%\]}' eval temp='${temp%\]}'
eval setname='${1%\[*}' eval setname='${1%\[*}'
@ -709,7 +709,7 @@ get_set_flags() # $1 = set name and optional [levels], $2 = src or dst
temp=$(($temp - 1)) temp=$(($temp - 1))
done done
;; ;;
$secondcase) *\[*\])
eval options='${1#*\[}' eval options='${1#*\[}'
eval options='${options%\]}' eval options='${options%\]}'
eval setname='${1%\[*}' eval setname='${1%\[*}'
@ -1270,7 +1270,7 @@ rulenum=0
find_interface_addresses $interface | while read address; do find_interface_addresses $interface | while read address; do
qt ip rule del from \$address qt ip rule del from \$address
pref=\$((20000 + \$rulenum * 1000 + $number )) pref=\$((20000 + ($number - 1) * 256 + \$rulenum ))
rulenum=\$((\$rulenum + 1)) rulenum=\$((\$rulenum + 1))
run_ip rule add from \$address pref \$pref table $number run_ip rule add from \$address pref \$pref table $number
done done
@ -1287,6 +1287,56 @@ __EOF__
fi fi
} }
verify_provider()
{
local p n
for p in $PROVIDERS; do
[ "$p" = "$1" ] && return 0
eval n=\$${p}_number}
[ "$n" = "$1" ] && return 0
done
fatal_error "Unknown provider $1 in rtrule \"$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"
progress_message "Routing rule \"$rule\" $DONE"
}
strip_file providers $1 strip_file providers $1
if [ -s $TMP_DIR/providers ]; then if [ -s $TMP_DIR/providers ]; then
@ -1333,6 +1383,20 @@ __EOF__
\${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables \${echobin:-echo} -e "$number\t$table" >> /etc/iproute2/rt_tables
__EOF__ __EOF__
done done
f=$(find_file rtrules)
if [ -f $f ]; then
progress_message2 "$DOING $f..."
strip_file rtrules $f
while read provider priority source dest; do
expandv priority provider source dest
rule="$priority $provider $source $dest"
add_an_rtrule
done < $TMP_DIR/rtrules
fi
fi fi
save_command "run_ip route flush cache" save_command "run_ip route flush cache"
@ -3113,6 +3177,11 @@ process_tc_rule()
[ $chain = tcpost ] || chain=tcout [ $chain = tcpost ] || chain=tcout
r="$(source_ip_range ${source#*:}) " r="$(source_ip_range ${source#*:}) "
;; ;;
*:*)
interface=${source%:*}
verify_interface $interface || fatal_error "Unknown interface $interface in rule \"$rule\""
r="$(match_source_dev $interface) $(source_ip_range ${source#*:}) "
;;
*.*.*|+*|!+*) *.*.*|+*|!+*)
r="$(source_ip_range $source) " r="$(source_ip_range $source) "
;; ;;
@ -3160,11 +3229,17 @@ process_tc_rule()
if [ "x$dest" != "x-" ]; then if [ "x$dest" != "x-" ]; then
case $dest in case $dest in
*:*)
[ "$chain" = tcpre ] && fatal_error "Destination interface is not allowed in the PREROUTING chain - rule \"$rule\""
interface=${dest%:*}
verify_interface $interface || fatal_error "Unknown interface $interface in rule \"$rule\""
r="$(match_dest_dev $interface) $(dest_ip_range ${dest#*:}) "
;;
*.*.*|+*|!+*) *.*.*|+*|!+*)
r="${r}$(dest_ip_range $dest) " r="${r}$(dest_ip_range $dest) "
;; ;;
*) *)
[ "$chain" = tcpre ] && fatal_error "Destination interface is not allowed in the PREROUTING chain" [ "$chain" = tcpre ] && fatal_error "Destination interface is not allowed in the PREROUTING chain - rule \"$rule\""
verify_interface $dest || fatal_error "Unknown interface $dest in rule \"$rule\"" verify_interface $dest || fatal_error "Unknown interface $dest in rule \"$rule\""
r="${r}$(match_dest_dev $dest) " r="${r}$(match_dest_dev $dest) "
;; ;;

View File

@ -292,12 +292,12 @@ separate_list() {
*\[*\]*) *\[*\]*)
# #
# Where we need to embed comma-separated lists within lists, we enclose them # Where we need to embed comma-separated lists within lists, we enclose them
# within square brackets # within square brackets (extra 'evals' are to keep my text editor (kate) from getting lost).
# #
firstpart=${list%%\[*} eval 'firstpart=${list%%\[*}'
lastpart=${list#*\[} eval 'lastpart=${list#*\[}'
enclosure=${lastpart%%\]*} eval 'enclosure=${lastpart%%\]*}'
lastpart=${lastpart#*\]} eval 'lastpart=${lastpart#*\]}'
case $lastpart in case $lastpart in
\,*) \,*)
case $firstpart in case $firstpart in
@ -593,10 +593,6 @@ strip_file() # $1 = Base Name of the file, $2 = Full Name of File (optional)
# behavior when the shell only supports 32-bit signed arithmatic and # behavior when the shell only supports 32-bit signed arithmatic and
# the IP address is 128.0.0.0 or 128.0.0.1. # the IP address is 128.0.0.0 or 128.0.0.1.
# #
#
# So that emacs doesn't get lost, we use $LEFTSHIFT rather than <<
#
LEFTSHIFT='<<'
# #
# Convert an IP address in dot quad format to an integer # Convert an IP address in dot quad format to an integer
@ -609,7 +605,7 @@ decodeaddr() {
IFS=. IFS=.
for x in $1; do for x in $1; do
temp=$(( $(( $temp $LEFTSHIFT 8 )) | $x )) temp=$(( $(( $temp << 8 )) | $x ))
done done
echo $temp echo $temp
@ -721,7 +717,7 @@ ip_range_explicit() {
ip_netmask() { ip_netmask() {
local vlsm=${1#*/} local vlsm=${1#*/}
[ $vlsm -eq 0 ] && echo 0 || echo $(( -1 $LEFTSHIFT $(( 32 - $vlsm )) )) [ $vlsm -eq 0 ] && echo 0 || echo $(( -1 << $(( 32 - $vlsm )) ))
} }
# #
@ -742,7 +738,7 @@ ip_network() {
ip_broadcast() { ip_broadcast() {
local x=$(( 32 - ${1#*/} )) local x=$(( 32 - ${1#*/} ))
[ $x -eq 0 ] && echo -1 || echo $(( $(( 1 $LEFTSHIFT $x )) - 1 )) [ $x -eq 0 ] && echo -1 || echo $(( $(( 1 << $x )) - 1 ))
} }
# #
@ -772,10 +768,10 @@ in_network() # $1 = IP address, $2 = CIDR network
ip_vlsm() { ip_vlsm() {
local mask=$(decodeaddr $1) local mask=$(decodeaddr $1)
local vlsm=0 local vlsm=0
local x=$(( 128 $LEFTSHIFT 24 )) # 0x80000000 local x=$(( 128 << 24 )) # 0x80000000
while [ $(( $x & $mask )) -ne 0 ]; do while [ $(( $x & $mask )) -ne 0 ]; do
[ $mask -eq $x ] && mask=0 || mask=$(( $mask $LEFTSHIFT 1 )) # Not all shells shift 0x80000000 left properly. [ $mask -eq $x ] && mask=0 || mask=$(( $mask << 1 )) # Not all shells shift 0x80000000 left properly.
vlsm=$(($vlsm + 1)) vlsm=$(($vlsm + 1))
done done
@ -838,7 +834,7 @@ if_match() # $1 = Name in interfaces file - may end in "+"
# #
source_ip_range() # $1 = Address or Address Range source_ip_range() # $1 = Address or Address Range
{ {
case $1 in [ $# -gt 0 ] && case $1 in
*.*.*.*-*.*.*.*) *.*.*.*-*.*.*.*)
case $1 in case $1 in
!*) !*)
@ -866,7 +862,7 @@ source_ip_range() # $1 = Address or Address Range
# #
dest_ip_range() # $1 = Address or Address Range dest_ip_range() # $1 = Address or Address Range
{ {
case $1 in [ $# -gt 0 ] && case $1 in
*.*.*.*-*.*.*.*) *.*.*.*-*.*.*.*)
case $1 in case $1 in
!*) !*)

View File

@ -38,7 +38,55 @@ Problems Corrected in 3.2.0 Beta 4
Other changes in 3.2.0 Beta 4 Other changes in 3.2.0 Beta 4
None. 1) Shorewall now includes support for explicit routing rules when the
/etc/shorewall/providers file is used. A new file, /etc/shorewall/rtrules
can be used to add routing rules based on packet source and/or
destination.
The file has the following columns:
PROVIDER The provider to route the traffic through.
May be expressed either as the provider name
or the provider number.
PRIORITY
The rule's priority which determines the order
in which the rules are processed.
1000-1999 Before Shorewall-generated
'MARK' rules
11000- 11999 After 'MARK' rules but before
Shorewall-generated rules for
ISP interfaces.
26000-26999 After ISP interface rules but
before 'default' rule.
Rules with equal priority are applied in
the order in which they appear in the file.
SOURCE(optonal) An ip address (network or host) that
matches the source IP address in a packet.
May also be specified as an interface
name optionally followed by ":" and an
address. If the define 'lo' is specified,
the packet must originate from the firewall
itself.
DEST(optional) An ip address (network or host) that
matches the destination IP address in a packet.
If you choose to omit either SOURCE or DEST,
place "-" in that column (or you can simply
leave the DEST column empty). Note that you
may not omit both SOURCE and DEST.
Example: You want all traffic coming in on eth1 to be routed to the ISP1
provider:
#PROVIDER PRIORITY SOURCE DEST
ISP1 1000 eth1
Migration Considerations: Migration Considerations:

View File

@ -84,10 +84,13 @@
# SOURCE Source of the packet. A comma-separated list of # SOURCE Source of the packet. A comma-separated list of
# interface names, IP addresses, MAC addresses and/or # interface names, IP addresses, MAC addresses and/or
# subnets for packets being routed through a common path. # subnets for packets being routed through a common path.
# For example, all packets for connections masqueraded # List elements may also consist of an interface name
# to eth0 from other interfaces can be matched in a # followed by ":" and an address
# single rule with several alternative SOURCE criteria. # (e.g., eth1:192.168.1.0/24). For example, all packets
# However, a connection whose packets gets to eth0 in a # for connections masqueraded to eth0 from other
# interfaces can be matched in a single rule with
# several alternative SOURCE criteria. However, a
# connection whose packets gets to eth0 in a
# different way, e.g., direct from the firewall itself, # different way, e.g., direct from the firewall itself,
# needs a different rule. # needs a different rule.
# #
@ -105,8 +108,9 @@
# DEST Destination of the packet. Comma separated list of # DEST Destination of the packet. Comma separated list of
# IP addresses and/or subnets. If your kernel and # IP addresses and/or subnets. If your kernel and
# iptables include iprange match support, IP address # iptables include iprange match support, IP address
# ranges are also allowed. # ranges are also allowed. List elements may also
# # consist of an interface name followed by ":" and an
# address (e.g., eth1:192.168.1.0/24).
# If the MARK column specificies a classification of # If the MARK column specificies a classification of
# the form <major>:<minor> then this column may also # the form <major>:<minor> then this column may also
# contain an interface name. # contain an interface name.