mirror of
https://gitlab.com/shorewall/code.git
synced 2025-01-09 23:28:13 +01:00
Restore the ability to refresh traffic control
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@3873 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
f854202304
commit
1ebb13cf08
@ -1,3 +1,9 @@
|
|||||||
|
Changes in 3.2.0 Beta 7
|
||||||
|
|
||||||
|
1) Fix mark/mask validation.
|
||||||
|
|
||||||
|
2) Restore traffic control to 'refresh'.
|
||||||
|
|
||||||
Changes in 3.2.0 Beta 6
|
Changes in 3.2.0 Beta 6
|
||||||
|
|
||||||
1) Fix tc "notfound" errors when 'restart' is run out of ip-up.local.
|
1) Fix tc "notfound" errors when 'restart' is run out of ip-up.local.
|
||||||
|
@ -1097,36 +1097,6 @@ __EOF__
|
|||||||
[ -z "$ALL_INTERFACES" ] && fatal_error "No Interfaces Defined"
|
[ -z "$ALL_INTERFACES" ] && fatal_error "No Interfaces Defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
|
||||||
# Check that a mark value or mask is less that 256 or that it is less than 65536 and
|
|
||||||
# that it's lower 8 bits are zero.
|
|
||||||
#
|
|
||||||
verify_mark() # $1 = value to test
|
|
||||||
{
|
|
||||||
verify_mark2()
|
|
||||||
{
|
|
||||||
case $1 in
|
|
||||||
0*)
|
|
||||||
[ $(($1)) -lt 256 ] && return 0
|
|
||||||
[ -n "$HIGH_ROUTE_MARKS" ] || return 1
|
|
||||||
[ $(($1)) -gt 65535 ] && return 1
|
|
||||||
return $(($1 & 0xFF))
|
|
||||||
;;
|
|
||||||
[1-9]*)
|
|
||||||
[ $1 -lt 256 ] && return 0
|
|
||||||
[ -n "$HIGH_ROUTE_MARKS" ] || return 1
|
|
||||||
[ $1 -gt 65535 ] && return 1
|
|
||||||
return $(($1 & 0xFF))
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
return 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_mark2 $1 || fatal_error "Invalid Mark or Mask value: $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Process the providers file
|
# Process the providers file
|
||||||
#
|
#
|
||||||
@ -2936,600 +2906,6 @@ build_exclusion_chain() # $1 = variable to store chain name into $2 = table, $3
|
|||||||
eval $1=$c
|
eval $1=$c
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
|
||||||
# Arne Bernin's 'tc4shorewall'
|
|
||||||
#
|
|
||||||
setup_traffic_shaping()
|
|
||||||
{
|
|
||||||
local mtu r2q tc_all_devices device mark rate ceil prio options devfile=$(find_file tcdevices) classfile=$(find_file tcclasses) devnum=1
|
|
||||||
mtu=1500
|
|
||||||
r2q=10
|
|
||||||
|
|
||||||
rate_to_kbit() {
|
|
||||||
local rateunit rate
|
|
||||||
rate=$1
|
|
||||||
rateunit=$( echo $rate | sed -e 's/[0-9]*//')
|
|
||||||
rate=$( echo $rate | sed -e 's/[a-z]*//g')
|
|
||||||
|
|
||||||
case $rateunit in
|
|
||||||
kbit)
|
|
||||||
rate=$rate
|
|
||||||
;;
|
|
||||||
mbit)
|
|
||||||
rate=$(expr $rate \* 1024)
|
|
||||||
;;
|
|
||||||
mbps)
|
|
||||||
rate=$(expr $rate \* 8192)
|
|
||||||
;;
|
|
||||||
kbps)
|
|
||||||
rate=$(expr $rate \* 8)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
rate=$(expr $rate / 128)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo $rate
|
|
||||||
}
|
|
||||||
|
|
||||||
calculate_quantum() {
|
|
||||||
local rate
|
|
||||||
rate=$1
|
|
||||||
rate=$(rate_to_kbit $rate)
|
|
||||||
rate=$(expr $rate \* 128 / $r2q )
|
|
||||||
if [ $rate -lt $mtu ] ; then
|
|
||||||
echo $mtu
|
|
||||||
else
|
|
||||||
echo $rate
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# get given outbandwidth for device
|
|
||||||
get_outband_for_dev() {
|
|
||||||
local device inband outband
|
|
||||||
while read device inband outband; do
|
|
||||||
expandv device inband outband
|
|
||||||
tcdev="$device $inband $outband"
|
|
||||||
if [ "$1" = "$device" ] ; then
|
|
||||||
echo $outband
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
done < $TMP_DIR/tcdevices
|
|
||||||
}
|
|
||||||
|
|
||||||
check_tcclasses_options() {
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
shift
|
|
||||||
case $1 in
|
|
||||||
default|tcp-ack|tos-minimize-delay|tos-maximize-throughput|tos-maximize-reliability|tos-minimize-cost|tos-normal-service)
|
|
||||||
;;
|
|
||||||
tos=0x[0-9a-f][0-9a-f]|tos=0x[0-9a-f][0-9a-f]/0x[0-9a-f][0-9a-f])
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo $1
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
get_defmark_for_dev() {
|
|
||||||
local searchdev searchmark device ceil prio options
|
|
||||||
searchdev=$1
|
|
||||||
|
|
||||||
while read device mark rate ceil prio options; do
|
|
||||||
expandv device mark rate ceil prio options
|
|
||||||
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
|
||||||
tcdev="$device $mark $rate $ceil $prio $options"
|
|
||||||
if [ "$searchdev" = "$device" ] ; then
|
|
||||||
list_search "default" $options && echo $mark &&return 0
|
|
||||||
fi
|
|
||||||
done < $TMP_DIR/tcclasses
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
check_defmark_for_dev() {
|
|
||||||
get_defmark_for_dev $1 >/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_tcdevices_file() {
|
|
||||||
progress_message2 "Validating $devfile..."
|
|
||||||
local device local device inband outband
|
|
||||||
while read device inband outband; do
|
|
||||||
expandv device inband outband
|
|
||||||
tcdev="$device $inband $outband"
|
|
||||||
check_defmark_for_dev $device || fatal_error "Option default is not defined for any class in tcclasses for interface $device"
|
|
||||||
case $interface in
|
|
||||||
*:*|+)
|
|
||||||
fatal_error "Invalid Interface Name: $interface"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
list_search $device $devices && fatal_error "Interface $device is defined more than once in tcdevices"
|
|
||||||
tc_all_devices="$tc_all_devices $device"
|
|
||||||
done < $TMP_DIR/tcdevices
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_tcclasses_file() {
|
|
||||||
progress_message2 "Validating $classfile..."
|
|
||||||
local classlist device mark rate ceil prio bandw wrongopt allopts opt
|
|
||||||
allopts=""
|
|
||||||
while read device mark rate ceil prio options; do
|
|
||||||
expandv device mark rate ceil prio options
|
|
||||||
tcdev="$device $mark $rate $ceil $prio $options"
|
|
||||||
ratew=$(get_outband_for_dev $device)
|
|
||||||
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
|
||||||
for opt in $options; do
|
|
||||||
case $opt in
|
|
||||||
tos=0x??)
|
|
||||||
opt="$opt/0xff"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
list_search "$device-$opt" $allopts && fatal_error "option $opt already defined in a chain for interface $device in tcclasses"
|
|
||||||
allopts="$allopts $device-$opt"
|
|
||||||
done
|
|
||||||
wrongopt=$(check_tcclasses_options $options) || fatal_error "unknown option $wrongopt for class iface $device mark $mark in tcclasses file"
|
|
||||||
if [ -z "$ratew" ] ; then
|
|
||||||
fatal_error "device $device seems not to be configured in tcdevices"
|
|
||||||
fi
|
|
||||||
list_search "$device-$mark" $classlist && fatal_error "Mark $mark for interface $device defined more than once in tcclasses"
|
|
||||||
#
|
|
||||||
# Convert HEX/OCTAL mark representation to decimal
|
|
||||||
#
|
|
||||||
mark=$(($mark))
|
|
||||||
verify_mark $mark
|
|
||||||
[ $mark -lt 256 ] || fatal_error "Invalid Mark Value"
|
|
||||||
classlist="$classlist $device-$mark"
|
|
||||||
done < $TMP_DIR/tcclasses
|
|
||||||
}
|
|
||||||
|
|
||||||
add_root_tc() {
|
|
||||||
local defmark
|
|
||||||
defmark=$(get_defmark_for_dev $device)
|
|
||||||
save_command qt tc qdisc del dev $device root
|
|
||||||
save_command qt tc qdisc del dev $device ingress
|
|
||||||
run_tc qdisc add dev $device root handle $devnum: htb default 1$defmark
|
|
||||||
run_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $outband
|
|
||||||
run_tc qdisc add dev $device handle ffff: ingress
|
|
||||||
run_tc filter add dev $device parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate ${inband} burst 10k drop flowid :1
|
|
||||||
eval $(chain_base $device)_devnum=$devnum
|
|
||||||
devnum=$(($devnum + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
add_tc_class() {
|
|
||||||
local full classid tospair tosmask
|
|
||||||
full=$(get_outband_for_dev $device)
|
|
||||||
full=$(rate_to_kbit $full)
|
|
||||||
|
|
||||||
if [ -z "$prio" ] ; then
|
|
||||||
prio=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $rate in
|
|
||||||
*full*)
|
|
||||||
rate=$(echo $rate | sed -e "s/full/$full/")
|
|
||||||
rate="$(($rate))kbit"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case $ceil in
|
|
||||||
*full*)
|
|
||||||
ceil=$(echo $ceil | sed -e "s/full/$full/")
|
|
||||||
ceil="$(($ceil))kbit"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
eval devnum=\$$(chain_base $device)_devnum
|
|
||||||
#
|
|
||||||
# Convert HEX/OCTAL mark representation to decimal
|
|
||||||
#
|
|
||||||
mark=$(($mark))
|
|
||||||
|
|
||||||
classid=$devnum:1$mark
|
|
||||||
|
|
||||||
[ -n "$devnum" ] || fatal_error "Device $device not defined in $devfile"
|
|
||||||
|
|
||||||
run_tc class add dev $device parent $devnum:1 classid $classid htb rate $rate ceil $ceil prio $prio quantum $(calculate_quantum $rate)
|
|
||||||
run_tc qdisc add dev $device parent $classid handle 1$mark: sfq perturb 10
|
|
||||||
# add filters
|
|
||||||
if [ -n "$CLASSIFY_TARGET" ]; then
|
|
||||||
run_iptables -t mangle -A tcpost $(match_dest_dev $device) -m mark --mark $mark/0xFF -j CLASSIFY --set-class $classid
|
|
||||||
else
|
|
||||||
run_tc filter add dev $device protocol ip parent $devnum:0 prio 1 handle $mark fw classid $classid
|
|
||||||
fi
|
|
||||||
#options
|
|
||||||
list_search "tcp-ack" $options && run_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip protocol 6 0xff match u8 0x05 0x0f at 0 match u16 0x0000 0xffc0 at 2 match u8 0x10 0xff at 33 flowid $classid
|
|
||||||
list_search "tos-minimize-delay" $options && options="$options tos=0x10/0x10"
|
|
||||||
list_search "tos-maximize-throughput" $options && options="$options tos=0x08/0x08"
|
|
||||||
list_search "tos-maximize-reliability" $options && options="$options tos=0x04/0x04"
|
|
||||||
list_search "tos-minimize-cost" $options && options="$options tos=0x02/0x02"
|
|
||||||
list_search "tos-normal-service" $options && options="$options tos=0x00/0x1e"
|
|
||||||
|
|
||||||
for tospair in $(list_walk "tos=" $options) ; do
|
|
||||||
case $tospair in
|
|
||||||
*/*)
|
|
||||||
tosmask=${tospair##*/}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
tosmask=0xff
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
run_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos ${tospair%%/*} $tosmask flowid $classid
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
strip_file tcdevices $devfile
|
|
||||||
strip_file tcclasses $classfile
|
|
||||||
|
|
||||||
validate_tcdevices_file
|
|
||||||
validate_tcclasses_file
|
|
||||||
|
|
||||||
if [ -s $TMP_DIR/tcdevices ]; then
|
|
||||||
save_progress_message "Setting up Traffic Control..."
|
|
||||||
progress_message2 "$DOING $devfile..."
|
|
||||||
|
|
||||||
while read device inband outband defmark ackmark; do
|
|
||||||
expandv device inband outband defmark ackmark
|
|
||||||
tcdev="$device $inband $outband"
|
|
||||||
add_root_tc
|
|
||||||
progress_message_and_save " TC Device $tcdev defined."
|
|
||||||
done < $TMP_DIR/tcdevices
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -s $TMP_DIR/tcclasses ]; then
|
|
||||||
progress_message2 "$DOING $classfile..."
|
|
||||||
|
|
||||||
while read device mark rate ceil prio options; do
|
|
||||||
expandv device mark rate ceil prio options
|
|
||||||
tcdev="$device $mark $rate $ceil $prio $options"
|
|
||||||
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
|
||||||
add_tc_class
|
|
||||||
progress_message_and_save " TC Class $tcdev defined."
|
|
||||||
done < $TMP_DIR/tcclasses
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process a TC Rule - $MARKING_CHAIN is assumed to contain the name of the
|
|
||||||
# default marking chain
|
|
||||||
#
|
|
||||||
process_tc_rule()
|
|
||||||
{
|
|
||||||
local did_connmark=
|
|
||||||
|
|
||||||
chain=$MARKING_CHAIN target="MARK --set-mark" marktest=
|
|
||||||
|
|
||||||
verify_designator() {
|
|
||||||
[ "$chain" = tcout ] && \
|
|
||||||
fatal_error "Chain designator not allowed when source is \$FW; rule \"$rule\""
|
|
||||||
chain=$1
|
|
||||||
mark="${mark%:*}"
|
|
||||||
}
|
|
||||||
|
|
||||||
do_ipp2p()
|
|
||||||
{
|
|
||||||
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\""
|
|
||||||
[ "x$port" = "x-" ] && port="ipp2p"
|
|
||||||
|
|
||||||
case $proto in
|
|
||||||
*:*)
|
|
||||||
proto=${proto#*:}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
proto=tcp
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
r="${r}-p $proto -m ipp2p --${port} "
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_small_mark()
|
|
||||||
{
|
|
||||||
verify_mark $1
|
|
||||||
[ $(($1)) -lt 256 ] || fatal_error "Mark Value ($1) too larg, rule \"$rule\""
|
|
||||||
}
|
|
||||||
|
|
||||||
do_connmark()
|
|
||||||
{
|
|
||||||
target="CONNMARK --set-mark"
|
|
||||||
mark=$mark/0xff
|
|
||||||
did_connmark=Yes
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_mark()
|
|
||||||
{
|
|
||||||
case $1 in
|
|
||||||
*/*)
|
|
||||||
verify_mark ${1%/*}
|
|
||||||
verify_mark ${1#*/}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
verify_mark $1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
add_a_tc_rule() {
|
|
||||||
r=
|
|
||||||
|
|
||||||
if [ "x$source" != "x-" ]; then
|
|
||||||
case $source in
|
|
||||||
$FW:*)
|
|
||||||
[ $chain = tcpost ] || chain=tcout
|
|
||||||
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="$(mac_match $source) "
|
|
||||||
;;
|
|
||||||
$FW)
|
|
||||||
[ $chain = tcpost ] || chain=tcout
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
verify_interface $source || fatal_error "Unknown interface $source in rule \"$rule\""
|
|
||||||
r="$(match_source_dev $source) "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "x${user:--}" != "x-" ]; then
|
|
||||||
|
|
||||||
[ "$chain" != tcout ] && \
|
|
||||||
fatal_error "Invalid use of a user/group: rule \"$rule\""
|
|
||||||
|
|
||||||
r="$r-m owner"
|
|
||||||
|
|
||||||
case "$user" in
|
|
||||||
*+*)
|
|
||||||
r="$r --cmd-owner ${user#*+} "
|
|
||||||
user=${user%+*}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$user" in
|
|
||||||
*:*)
|
|
||||||
temp="${user%:*}"
|
|
||||||
[ -n "$temp" ] && r="$r --uid-owner $temp "
|
|
||||||
temp="${user#*:}"
|
|
||||||
[ -n "$temp" ] && r="$r --gid-owner $temp "
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ -n "$user" ] && r="$r --uid-owner $user "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
[ -n "$marktest" ] && r="${r}-m ${marktest}--mark $testval "
|
|
||||||
|
|
||||||
if [ "x$dest" != "x-" ]; then
|
|
||||||
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) "
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ "$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\""
|
|
||||||
r="${r}$(match_dest_dev $dest) "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "x${length:=-}" != "x-" ]; then
|
|
||||||
[ -n "$LENGTH_MATCH" ] || fatal_error "Your kernel and/or iptables does not have length match support. Rule: \"$rule\""
|
|
||||||
r="${r}-m length --length ${length} "
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "x${tos:=-}" != "x-" ]; then
|
|
||||||
r="${r}-m tos --tos ${tos} "
|
|
||||||
fi
|
|
||||||
|
|
||||||
multiport=
|
|
||||||
|
|
||||||
case $proto in
|
|
||||||
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
|
|
||||||
do_ipp2p
|
|
||||||
;;
|
|
||||||
icmp|ICMP|1)
|
|
||||||
r="${r}-p icmp "
|
|
||||||
[ "x$port" = "x-" ] || r="${r}--icmp-type $port"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ "x$proto" = "x-" ] && proto=all
|
|
||||||
[ "x$proto" = "x" ] && proto=all
|
|
||||||
[ "$proto" = "all" ] || r="${r}-p $proto "
|
|
||||||
[ "x$port" = "x-" ] || r="${r}--dport $port "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
[ "x$sport" = "x-" ] || r="${r}--sport $sport "
|
|
||||||
|
|
||||||
if [ -n "${excludesources}${excludedests}" ]; then
|
|
||||||
build_exclusion_chain chain1 mangle "$excludesources" "$excludedests"
|
|
||||||
|
|
||||||
run_iptables2 -t mangle -A $chain $r -j $chain1
|
|
||||||
|
|
||||||
run_iptables -t mangle -A $chain1 -j $target $mark
|
|
||||||
else
|
|
||||||
run_iptables2 -t mangle -A $chain $r -j $target $mark
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$mark" != "${mark%:*}" ]; then
|
|
||||||
case "${mark#*:}" in
|
|
||||||
p|P)
|
|
||||||
verify_designator tcpre
|
|
||||||
;;
|
|
||||||
cp|CP)
|
|
||||||
verify_designator tcpre
|
|
||||||
do_connmark
|
|
||||||
;;
|
|
||||||
f|F)
|
|
||||||
verify_designator tcfor
|
|
||||||
;;
|
|
||||||
cf|CF)
|
|
||||||
verify_designator tcfor
|
|
||||||
do_connmark
|
|
||||||
;;
|
|
||||||
c|C)
|
|
||||||
mark=${mark%:*}
|
|
||||||
do_connmark
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
chain=tcpost
|
|
||||||
target="CLASSIFY --set-class"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
mask=0xffff
|
|
||||||
|
|
||||||
case $mark in
|
|
||||||
SAVE)
|
|
||||||
[ -n "$did_connmark" ] && fatal_error "SAVE not valid with :C[FP]"
|
|
||||||
target="CONNMARK --save-mark --mask 0xFF"
|
|
||||||
mark=
|
|
||||||
;;
|
|
||||||
SAVE/*)
|
|
||||||
[ -n "$did_connmark" ] && fatal_error "SAVE not valid with :C[FP]"
|
|
||||||
target="CONNMARK --save-mark --mask"
|
|
||||||
mark=${mark#*/}
|
|
||||||
verify_small_mark $mark
|
|
||||||
;;
|
|
||||||
RESTORE)
|
|
||||||
[ -n "$did_connmark" ] && fatal_error "RESTORE not valid with :C[FP]"
|
|
||||||
target="CONNMARK --restore-mark --mask 0xFF"
|
|
||||||
mark=
|
|
||||||
;;
|
|
||||||
RESTORE/*)
|
|
||||||
[ -n "$did_connmark" ] && fatal_error "RESTORE not valid with :C[FP]"
|
|
||||||
target="CONNMARK --restore-mark --mask"
|
|
||||||
mark=${mark#*/}
|
|
||||||
verify_small_mark $mark
|
|
||||||
;;
|
|
||||||
CONTINUE)
|
|
||||||
[ -n "$did_connmark" ] && fatal_error "CONTINUE not valid with :C[FP]"
|
|
||||||
target=RETURN
|
|
||||||
mark=
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ "$chain" != tcpost ]; then
|
|
||||||
validate_mark $mark
|
|
||||||
if [ $((${mark%/*})) -gt 255 ]; then
|
|
||||||
case $chain in
|
|
||||||
tcpre|tcout)
|
|
||||||
target="MARK --or-mark"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
fatal_error "Invalid mark value ($mark) in rule \"$rule\""
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
elif [ $((${mark%/*})) -ne 0 -a -n "$HIGH_ROUTE_MARKS" -a $chain = tcpre ]; then
|
|
||||||
fatal_error "Marks < 256 may not be set in the PREROUTING chain when HIGH_ROUTE_MARKS=Yes"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case $testval in
|
|
||||||
-)
|
|
||||||
;;
|
|
||||||
!*:C)
|
|
||||||
marktest="connmark ! "
|
|
||||||
testval=${testval%:*}
|
|
||||||
testval=${testval#!}
|
|
||||||
;;
|
|
||||||
*:C)
|
|
||||||
marktest="connmark "
|
|
||||||
testval=${testval%:*}
|
|
||||||
;;
|
|
||||||
!*)
|
|
||||||
marktest="mark ! "
|
|
||||||
testval=${testval#!}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ -n "$testval" ] && marktest="mark "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$marktest" ] ; then
|
|
||||||
case $testval in
|
|
||||||
*/*)
|
|
||||||
verify_mark ${testval%/*}
|
|
||||||
verify_mark ${testval#*/}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
verify_mark $testval
|
|
||||||
testval=$testval/$mask
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
excludesources=
|
|
||||||
|
|
||||||
case ${sources:=-} in
|
|
||||||
*!*!*)
|
|
||||||
fatal_error "Invalid SOURCE in rule \"$rule\""
|
|
||||||
;;
|
|
||||||
!*)
|
|
||||||
if [ $(list_count $sourcess) -gt 1 ]; then
|
|
||||||
excludesources=${sources#!}
|
|
||||||
sources=-
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*!*)
|
|
||||||
excludesources=${sources#*!}
|
|
||||||
sources=${sources%!*}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
excludedests=
|
|
||||||
|
|
||||||
case ${dests:=-} in
|
|
||||||
*!*!*)
|
|
||||||
fatal_error "Invalid DEST in rule \"$rule\""
|
|
||||||
;;
|
|
||||||
!*)
|
|
||||||
if [ $(list_count $dests) -gt 1 ]; then
|
|
||||||
excludedests=${dests#*!}
|
|
||||||
dests=-
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*!*)
|
|
||||||
excludedests=${dests#*!}
|
|
||||||
dests=${dests%!*}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
for source in $(separate_list $sources); do
|
|
||||||
for dest in $(separate_list $dests); do
|
|
||||||
for port in $(separate_list ${ports:=-}); do
|
|
||||||
for sport in $(separate_list ${sports:=-}); do
|
|
||||||
add_a_tc_rule
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
progress_message " TC Rule \"$rule\" $DONE"
|
|
||||||
save_progress_message " TC Rule \"$rule\" Added"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Setup queuing and classes
|
# Setup queuing and classes
|
||||||
#
|
#
|
||||||
|
@ -1742,12 +1742,77 @@ check_disabled_startup() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Dummy functions to make refresh_tc happy
|
||||||
|
#
|
||||||
|
save_progress_message()
|
||||||
|
{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
save_command()
|
||||||
|
{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
progress_message_and_save()
|
||||||
|
{
|
||||||
|
progress_message $@
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Refresh queuing and classes
|
||||||
|
#
|
||||||
|
refresh_tc() {
|
||||||
|
|
||||||
|
echo "Refreshing Traffic Control Rules..."
|
||||||
|
|
||||||
|
[ -n "$CLEAR_TC" ] && delete_tc1
|
||||||
|
|
||||||
|
[ -n "$MARK_IN_FORWARD_CHAIN" ] && chain=tcfor || chain=tcpre
|
||||||
|
|
||||||
|
#
|
||||||
|
# Flush the TC mangle chains
|
||||||
|
#
|
||||||
|
|
||||||
|
[ -n "$MANGLE_FORWARD" ] && run_iptables -t mangle -F tcfor
|
||||||
|
run_iptables -t mangle -F tcpre
|
||||||
|
run_iptables -t mangle -F tcout
|
||||||
|
run_iptables -t mangle -F tcpost
|
||||||
|
#
|
||||||
|
# Remove all exclusion chains from the mangle table
|
||||||
|
#
|
||||||
|
$IPTABLES -t mangle -L -n | grep '^Chain excl_' | while read junk chain rest; do
|
||||||
|
run_iptables -t mangle -F $chain
|
||||||
|
run_iptables -t mangle -X $chain
|
||||||
|
done
|
||||||
|
|
||||||
|
#
|
||||||
|
# Process the TC Rules File
|
||||||
|
#
|
||||||
|
strip_file tcrules
|
||||||
|
|
||||||
|
while read mark sources dests proto ports sports user testval; do
|
||||||
|
expandv mark sources dests proto ports sports user testval
|
||||||
|
rule=$(echo "$mark $sources $dests $proto $ports $sports $user $testval")
|
||||||
|
process_tc_rule
|
||||||
|
done < $TMP_DIR/tcrules
|
||||||
|
|
||||||
|
if [ -n "$TC_SCRIPT" ]; then
|
||||||
|
run_user_exit $TC_SCRIPT
|
||||||
|
elif [ -n "$TC_ENABLED" ]; then
|
||||||
|
setup_traffic_shaping
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Refresh the firewall
|
# Refresh the firewall
|
||||||
#
|
#
|
||||||
refresh_firewall()
|
refresh_firewall()
|
||||||
{
|
{
|
||||||
#
|
DOING=Refreshing
|
||||||
|
DONE=Refreshed
|
||||||
|
|
||||||
progress_message3 "Refreshing Shorewall..."
|
progress_message3 "Refreshing Shorewall..."
|
||||||
|
|
||||||
@ -1770,6 +1835,11 @@ refresh_firewall()
|
|||||||
|
|
||||||
[ -f $ecn ] && [ -n "$MANGLE_ENABLED" ] && setup_ecn $ecn
|
[ -f $ecn ] && [ -n "$MANGLE_ENABLED" ] && setup_ecn $ecn
|
||||||
|
|
||||||
|
#
|
||||||
|
# Refresh Traffic Control
|
||||||
|
#
|
||||||
|
[ -n "$MANGLE_ENABLED" ] && refresh_tc
|
||||||
|
|
||||||
run_user_exit refreshed
|
run_user_exit refreshed
|
||||||
|
|
||||||
report "Shorewall Refreshed"
|
report "Shorewall Refreshed"
|
||||||
|
@ -1442,6 +1442,630 @@ log_rule() # $1 = log level, $2 = chain, $3 = disposition , $... = predicates fo
|
|||||||
log_rule_limit $level $chain $chain $disposition "$LOGLIMIT" "" -A $@
|
log_rule_limit $level $chain $chain $disposition "$LOGLIMIT" "" -A $@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that a mark value or mask is less that 256 or that it is less than 65536 and
|
||||||
|
# that it's lower 8 bits are zero.
|
||||||
|
#
|
||||||
|
verify_mark() # $1 = value to test
|
||||||
|
{
|
||||||
|
verify_mark2()
|
||||||
|
{
|
||||||
|
case $1 in
|
||||||
|
0*)
|
||||||
|
[ $(($1)) -lt 256 ] && return 0
|
||||||
|
[ -n "$HIGH_ROUTE_MARKS" ] || return 1
|
||||||
|
[ $(($1)) -gt 65535 ] && return 1
|
||||||
|
return $(($1 & 0xFF))
|
||||||
|
;;
|
||||||
|
[1-9]*)
|
||||||
|
[ $1 -lt 256 ] && return 0
|
||||||
|
[ -n "$HIGH_ROUTE_MARKS" ] || return 1
|
||||||
|
[ $1 -gt 65535 ] && return 1
|
||||||
|
return $(($1 & 0xFF))
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_mark2 $1 || fatal_error "Invalid Mark or Mask value: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Arne Bernin's 'tc4shorewall'
|
||||||
|
#
|
||||||
|
setup_traffic_shaping()
|
||||||
|
{
|
||||||
|
local mtu r2q tc_all_devices device mark rate ceil prio options devfile=$(find_file tcdevices) classfile=$(find_file tcclasses) devnum=1
|
||||||
|
mtu=1500
|
||||||
|
r2q=10
|
||||||
|
|
||||||
|
rate_to_kbit() {
|
||||||
|
local rateunit rate
|
||||||
|
rate=$1
|
||||||
|
rateunit=$( echo $rate | sed -e 's/[0-9]*//')
|
||||||
|
rate=$( echo $rate | sed -e 's/[a-z]*//g')
|
||||||
|
|
||||||
|
case $rateunit in
|
||||||
|
kbit)
|
||||||
|
rate=$rate
|
||||||
|
;;
|
||||||
|
mbit)
|
||||||
|
rate=$(expr $rate \* 1024)
|
||||||
|
;;
|
||||||
|
mbps)
|
||||||
|
rate=$(expr $rate \* 8192)
|
||||||
|
;;
|
||||||
|
kbps)
|
||||||
|
rate=$(expr $rate \* 8)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
rate=$(expr $rate / 128)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo $rate
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_quantum() {
|
||||||
|
local rate
|
||||||
|
rate=$1
|
||||||
|
rate=$(rate_to_kbit $rate)
|
||||||
|
rate=$(expr $rate \* 128 / $r2q )
|
||||||
|
if [ $rate -lt $mtu ] ; then
|
||||||
|
echo $mtu
|
||||||
|
else
|
||||||
|
echo $rate
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# get given outbandwidth for device
|
||||||
|
get_outband_for_dev() {
|
||||||
|
local device inband outband
|
||||||
|
while read device inband outband; do
|
||||||
|
expandv device inband outband
|
||||||
|
tcdev="$device $inband $outband"
|
||||||
|
if [ "$1" = "$device" ] ; then
|
||||||
|
echo $outband
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done < $TMP_DIR/tcdevices
|
||||||
|
}
|
||||||
|
|
||||||
|
check_tcclasses_options() {
|
||||||
|
while [ $# -gt 1 ]; do
|
||||||
|
shift
|
||||||
|
case $1 in
|
||||||
|
default|tcp-ack|tos-minimize-delay|tos-maximize-throughput|tos-maximize-reliability|tos-minimize-cost|tos-normal-service)
|
||||||
|
;;
|
||||||
|
tos=0x[0-9a-f][0-9a-f]|tos=0x[0-9a-f][0-9a-f]/0x[0-9a-f][0-9a-f])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo $1
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get_defmark_for_dev() {
|
||||||
|
local searchdev searchmark device ceil prio options
|
||||||
|
searchdev=$1
|
||||||
|
|
||||||
|
while read device mark rate ceil prio options; do
|
||||||
|
expandv device mark rate ceil prio options
|
||||||
|
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
||||||
|
tcdev="$device $mark $rate $ceil $prio $options"
|
||||||
|
if [ "$searchdev" = "$device" ] ; then
|
||||||
|
list_search "default" $options && echo $mark &&return 0
|
||||||
|
fi
|
||||||
|
done < $TMP_DIR/tcclasses
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_defmark_for_dev() {
|
||||||
|
get_defmark_for_dev $1 >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_tcdevices_file() {
|
||||||
|
progress_message2 "Validating $devfile..."
|
||||||
|
local device local device inband outband
|
||||||
|
while read device inband outband; do
|
||||||
|
expandv device inband outband
|
||||||
|
tcdev="$device $inband $outband"
|
||||||
|
check_defmark_for_dev $device || fatal_error "Option default is not defined for any class in tcclasses for interface $device"
|
||||||
|
case $interface in
|
||||||
|
*:*|+)
|
||||||
|
fatal_error "Invalid Interface Name: $interface"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
list_search $device $devices && fatal_error "Interface $device is defined more than once in tcdevices"
|
||||||
|
tc_all_devices="$tc_all_devices $device"
|
||||||
|
done < $TMP_DIR/tcdevices
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_tcclasses_file() {
|
||||||
|
progress_message2 "Validating $classfile..."
|
||||||
|
local classlist device mark rate ceil prio bandw wrongopt allopts opt
|
||||||
|
allopts=""
|
||||||
|
while read device mark rate ceil prio options; do
|
||||||
|
expandv device mark rate ceil prio options
|
||||||
|
tcdev="$device $mark $rate $ceil $prio $options"
|
||||||
|
ratew=$(get_outband_for_dev $device)
|
||||||
|
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
||||||
|
for opt in $options; do
|
||||||
|
case $opt in
|
||||||
|
tos=0x??)
|
||||||
|
opt="$opt/0xff"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
list_search "$device-$opt" $allopts && fatal_error "option $opt already defined in a chain for interface $device in tcclasses"
|
||||||
|
allopts="$allopts $device-$opt"
|
||||||
|
done
|
||||||
|
wrongopt=$(check_tcclasses_options $options) || fatal_error "unknown option $wrongopt for class iface $device mark $mark in tcclasses file"
|
||||||
|
if [ -z "$ratew" ] ; then
|
||||||
|
fatal_error "device $device seems not to be configured in tcdevices"
|
||||||
|
fi
|
||||||
|
list_search "$device-$mark" $classlist && fatal_error "Mark $mark for interface $device defined more than once in tcclasses"
|
||||||
|
#
|
||||||
|
# Convert HEX/OCTAL mark representation to decimal
|
||||||
|
#
|
||||||
|
mark=$(($mark))
|
||||||
|
verify_mark $mark
|
||||||
|
[ $mark -lt 256 ] || fatal_error "Invalid Mark Value"
|
||||||
|
classlist="$classlist $device-$mark"
|
||||||
|
done < $TMP_DIR/tcclasses
|
||||||
|
}
|
||||||
|
|
||||||
|
add_root_tc() {
|
||||||
|
local defmark
|
||||||
|
defmark=$(get_defmark_for_dev $device)
|
||||||
|
save_command qt tc qdisc del dev $device root
|
||||||
|
save_command qt tc qdisc del dev $device ingress
|
||||||
|
run_tc qdisc add dev $device root handle $devnum: htb default 1$defmark
|
||||||
|
run_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $outband
|
||||||
|
run_tc qdisc add dev $device handle ffff: ingress
|
||||||
|
run_tc filter add dev $device parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate ${inband} burst 10k drop flowid :1
|
||||||
|
eval $(chain_base $device)_devnum=$devnum
|
||||||
|
devnum=$(($devnum + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
add_tc_class() {
|
||||||
|
local full classid tospair tosmask
|
||||||
|
full=$(get_outband_for_dev $device)
|
||||||
|
full=$(rate_to_kbit $full)
|
||||||
|
|
||||||
|
if [ -z "$prio" ] ; then
|
||||||
|
prio=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $rate in
|
||||||
|
*full*)
|
||||||
|
rate=$(echo $rate | sed -e "s/full/$full/")
|
||||||
|
rate="$(($rate))kbit"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case $ceil in
|
||||||
|
*full*)
|
||||||
|
ceil=$(echo $ceil | sed -e "s/full/$full/")
|
||||||
|
ceil="$(($ceil))kbit"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
eval devnum=\$$(chain_base $device)_devnum
|
||||||
|
#
|
||||||
|
# Convert HEX/OCTAL mark representation to decimal
|
||||||
|
#
|
||||||
|
mark=$(($mark))
|
||||||
|
|
||||||
|
classid=$devnum:1$mark
|
||||||
|
|
||||||
|
[ -n "$devnum" ] || fatal_error "Device $device not defined in $devfile"
|
||||||
|
|
||||||
|
run_tc class add dev $device parent $devnum:1 classid $classid htb rate $rate ceil $ceil prio $prio quantum $(calculate_quantum $rate)
|
||||||
|
run_tc qdisc add dev $device parent $classid handle 1$mark: sfq perturb 10
|
||||||
|
# add filters
|
||||||
|
if [ -n "$CLASSIFY_TARGET" ]; then
|
||||||
|
run_iptables -t mangle -A tcpost $(match_dest_dev $device) -m mark --mark $mark/0xFF -j CLASSIFY --set-class $classid
|
||||||
|
else
|
||||||
|
run_tc filter add dev $device protocol ip parent $devnum:0 prio 1 handle $mark fw classid $classid
|
||||||
|
fi
|
||||||
|
#options
|
||||||
|
list_search "tcp-ack" $options && run_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip protocol 6 0xff match u8 0x05 0x0f at 0 match u16 0x0000 0xffc0 at 2 match u8 0x10 0xff at 33 flowid $classid
|
||||||
|
list_search "tos-minimize-delay" $options && options="$options tos=0x10/0x10"
|
||||||
|
list_search "tos-maximize-throughput" $options && options="$options tos=0x08/0x08"
|
||||||
|
list_search "tos-maximize-reliability" $options && options="$options tos=0x04/0x04"
|
||||||
|
list_search "tos-minimize-cost" $options && options="$options tos=0x02/0x02"
|
||||||
|
list_search "tos-normal-service" $options && options="$options tos=0x00/0x1e"
|
||||||
|
|
||||||
|
for tospair in $(list_walk "tos=" $options) ; do
|
||||||
|
case $tospair in
|
||||||
|
*/*)
|
||||||
|
tosmask=${tospair##*/}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
tosmask=0xff
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
run_tc filter add dev $device parent $devnum:0 protocol ip prio 10 u32 match ip tos ${tospair%%/*} $tosmask flowid $classid
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
strip_file tcdevices $devfile
|
||||||
|
strip_file tcclasses $classfile
|
||||||
|
|
||||||
|
validate_tcdevices_file
|
||||||
|
validate_tcclasses_file
|
||||||
|
|
||||||
|
if [ -s $TMP_DIR/tcdevices ]; then
|
||||||
|
save_progress_message "Setting up Traffic Control..."
|
||||||
|
progress_message2 "$DOING $devfile..."
|
||||||
|
|
||||||
|
while read device inband outband defmark ackmark; do
|
||||||
|
expandv device inband outband defmark ackmark
|
||||||
|
tcdev="$device $inband $outband"
|
||||||
|
add_root_tc
|
||||||
|
progress_message_and_save " TC Device $tcdev defined."
|
||||||
|
done < $TMP_DIR/tcdevices
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s $TMP_DIR/tcclasses ]; then
|
||||||
|
progress_message2 "$DOING $classfile..."
|
||||||
|
|
||||||
|
while read device mark rate ceil prio options; do
|
||||||
|
expandv device mark rate ceil prio options
|
||||||
|
tcdev="$device $mark $rate $ceil $prio $options"
|
||||||
|
options=$(separate_list $options | tr '[A-Z]' '[a-z]')
|
||||||
|
add_tc_class
|
||||||
|
progress_message_and_save " TC Class $tcdev defined."
|
||||||
|
done < $TMP_DIR/tcclasses
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Process a TC Rule - $MARKING_CHAIN is assumed to contain the name of the
|
||||||
|
# default marking chain
|
||||||
|
#
|
||||||
|
process_tc_rule()
|
||||||
|
{
|
||||||
|
local did_connmark=
|
||||||
|
|
||||||
|
chain=$MARKING_CHAIN target="MARK --set-mark" marktest=
|
||||||
|
|
||||||
|
verify_designator() {
|
||||||
|
[ "$chain" = tcout ] && \
|
||||||
|
fatal_error "Chain designator not allowed when source is \$FW; rule \"$rule\""
|
||||||
|
chain=$1
|
||||||
|
mark="${mark%:*}"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_ipp2p()
|
||||||
|
{
|
||||||
|
[ -n "$IPP2P_MATCH" ] || fatal_error "Your kernel and/or iptables does not have IPP2P match support. Rule: \"$rule\""
|
||||||
|
[ "x$port" = "x-" ] && port="ipp2p"
|
||||||
|
|
||||||
|
case $proto in
|
||||||
|
*:*)
|
||||||
|
proto=${proto#*:}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
proto=tcp
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
r="${r}-p $proto -m ipp2p --${port} "
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_small_mark()
|
||||||
|
{
|
||||||
|
verify_mark $1
|
||||||
|
[ $(($1)) -lt 256 ] || fatal_error "Mark Value ($1) too larg, rule \"$rule\""
|
||||||
|
}
|
||||||
|
|
||||||
|
do_connmark()
|
||||||
|
{
|
||||||
|
target="CONNMARK --set-mark"
|
||||||
|
mark=$mark/0xff
|
||||||
|
did_connmark=Yes
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_mark()
|
||||||
|
{
|
||||||
|
case $1 in
|
||||||
|
*/*)
|
||||||
|
verify_mark ${1%/*}
|
||||||
|
verify_mark ${1#*/}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
verify_mark $1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
add_a_tc_rule() {
|
||||||
|
r=
|
||||||
|
|
||||||
|
if [ "x$source" != "x-" ]; then
|
||||||
|
case $source in
|
||||||
|
$FW:*)
|
||||||
|
[ $chain = tcpost ] || chain=tcout
|
||||||
|
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="$(mac_match $source) "
|
||||||
|
;;
|
||||||
|
$FW)
|
||||||
|
[ $chain = tcpost ] || chain=tcout
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
verify_interface $source || fatal_error "Unknown interface $source in rule \"$rule\""
|
||||||
|
r="$(match_source_dev $source) "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x${user:--}" != "x-" ]; then
|
||||||
|
|
||||||
|
[ "$chain" != tcout ] && \
|
||||||
|
fatal_error "Invalid use of a user/group: rule \"$rule\""
|
||||||
|
|
||||||
|
r="$r-m owner"
|
||||||
|
|
||||||
|
case "$user" in
|
||||||
|
*+*)
|
||||||
|
r="$r --cmd-owner ${user#*+} "
|
||||||
|
user=${user%+*}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$user" in
|
||||||
|
*:*)
|
||||||
|
temp="${user%:*}"
|
||||||
|
[ -n "$temp" ] && r="$r --uid-owner $temp "
|
||||||
|
temp="${user#*:}"
|
||||||
|
[ -n "$temp" ] && r="$r --gid-owner $temp "
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ -n "$user" ] && r="$r --uid-owner $user "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
[ -n "$marktest" ] && r="${r}-m ${marktest}--mark $testval "
|
||||||
|
|
||||||
|
if [ "x$dest" != "x-" ]; then
|
||||||
|
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) "
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ "$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\""
|
||||||
|
r="${r}$(match_dest_dev $dest) "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x${length:=-}" != "x-" ]; then
|
||||||
|
[ -n "$LENGTH_MATCH" ] || fatal_error "Your kernel and/or iptables does not have length match support. Rule: \"$rule\""
|
||||||
|
r="${r}-m length --length ${length} "
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "x${tos:=-}" != "x-" ]; then
|
||||||
|
r="${r}-m tos --tos ${tos} "
|
||||||
|
fi
|
||||||
|
|
||||||
|
multiport=
|
||||||
|
|
||||||
|
case $proto in
|
||||||
|
ipp2p|IPP2P|ipp2p:*|IPP2P:*)
|
||||||
|
do_ipp2p
|
||||||
|
;;
|
||||||
|
icmp|ICMP|1)
|
||||||
|
r="${r}-p icmp "
|
||||||
|
[ "x$port" = "x-" ] || r="${r}--icmp-type $port"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ "x$proto" = "x-" ] && proto=all
|
||||||
|
[ "x$proto" = "x" ] && proto=all
|
||||||
|
[ "$proto" = "all" ] || r="${r}-p $proto "
|
||||||
|
[ "x$port" = "x-" ] || r="${r}--dport $port "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ "x$sport" = "x-" ] || r="${r}--sport $sport "
|
||||||
|
|
||||||
|
if [ -n "${excludesources}${excludedests}" ]; then
|
||||||
|
build_exclusion_chain chain1 mangle "$excludesources" "$excludedests"
|
||||||
|
|
||||||
|
run_iptables2 -t mangle -A $chain $r -j $chain1
|
||||||
|
|
||||||
|
run_iptables -t mangle -A $chain1 -j $target $mark
|
||||||
|
else
|
||||||
|
run_iptables2 -t mangle -A $chain $r -j $target $mark
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$mark" != "${mark%:*}" ]; then
|
||||||
|
case "${mark#*:}" in
|
||||||
|
p|P)
|
||||||
|
verify_designator tcpre
|
||||||
|
;;
|
||||||
|
cp|CP)
|
||||||
|
verify_designator tcpre
|
||||||
|
do_connmark
|
||||||
|
;;
|
||||||
|
f|F)
|
||||||
|
verify_designator tcfor
|
||||||
|
;;
|
||||||
|
cf|CF)
|
||||||
|
verify_designator tcfor
|
||||||
|
do_connmark
|
||||||
|
;;
|
||||||
|
c|C)
|
||||||
|
mark=${mark%:*}
|
||||||
|
do_connmark
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
chain=tcpost
|
||||||
|
target="CLASSIFY --set-class"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
mask=0xffff
|
||||||
|
|
||||||
|
case $mark in
|
||||||
|
SAVE)
|
||||||
|
[ -n "$did_connmark" ] && fatal_error "SAVE not valid with :C[FP]"
|
||||||
|
target="CONNMARK --save-mark --mask 0xFF"
|
||||||
|
mark=
|
||||||
|
;;
|
||||||
|
SAVE/*)
|
||||||
|
[ -n "$did_connmark" ] && fatal_error "SAVE not valid with :C[FP]"
|
||||||
|
target="CONNMARK --save-mark --mask"
|
||||||
|
mark=${mark#*/}
|
||||||
|
verify_small_mark $mark
|
||||||
|
;;
|
||||||
|
RESTORE)
|
||||||
|
[ -n "$did_connmark" ] && fatal_error "RESTORE not valid with :C[FP]"
|
||||||
|
target="CONNMARK --restore-mark --mask 0xFF"
|
||||||
|
mark=
|
||||||
|
;;
|
||||||
|
RESTORE/*)
|
||||||
|
[ -n "$did_connmark" ] && fatal_error "RESTORE not valid with :C[FP]"
|
||||||
|
target="CONNMARK --restore-mark --mask"
|
||||||
|
mark=${mark#*/}
|
||||||
|
verify_small_mark $mark
|
||||||
|
;;
|
||||||
|
CONTINUE)
|
||||||
|
[ -n "$did_connmark" ] && fatal_error "CONTINUE not valid with :C[FP]"
|
||||||
|
target=RETURN
|
||||||
|
mark=
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$chain" != tcpost ]; then
|
||||||
|
validate_mark $mark
|
||||||
|
if [ $((${mark%/*})) -gt 255 ]; then
|
||||||
|
case $chain in
|
||||||
|
tcpre|tcout)
|
||||||
|
target="MARK --or-mark"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fatal_error "Invalid mark value ($mark) in rule \"$rule\""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
elif [ $((${mark%/*})) -ne 0 -a -n "$HIGH_ROUTE_MARKS" -a $chain = tcpre ]; then
|
||||||
|
fatal_error "Marks < 256 may not be set in the PREROUTING chain when HIGH_ROUTE_MARKS=Yes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case $testval in
|
||||||
|
-)
|
||||||
|
;;
|
||||||
|
!*:C)
|
||||||
|
marktest="connmark ! "
|
||||||
|
testval=${testval%:*}
|
||||||
|
testval=${testval#!}
|
||||||
|
;;
|
||||||
|
*:C)
|
||||||
|
marktest="connmark "
|
||||||
|
testval=${testval%:*}
|
||||||
|
;;
|
||||||
|
!*)
|
||||||
|
marktest="mark ! "
|
||||||
|
testval=${testval#!}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ -n "$testval" ] && marktest="mark "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$marktest" ] ; then
|
||||||
|
case $testval in
|
||||||
|
*/*)
|
||||||
|
verify_mark ${testval%/*}
|
||||||
|
verify_mark ${testval#*/}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
verify_mark $testval
|
||||||
|
testval=$testval/$mask
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
excludesources=
|
||||||
|
|
||||||
|
case ${sources:=-} in
|
||||||
|
*!*!*)
|
||||||
|
fatal_error "Invalid SOURCE in rule \"$rule\""
|
||||||
|
;;
|
||||||
|
!*)
|
||||||
|
if [ $(list_count $sourcess) -gt 1 ]; then
|
||||||
|
excludesources=${sources#!}
|
||||||
|
sources=-
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*!*)
|
||||||
|
excludesources=${sources#*!}
|
||||||
|
sources=${sources%!*}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
excludedests=
|
||||||
|
|
||||||
|
case ${dests:=-} in
|
||||||
|
*!*!*)
|
||||||
|
fatal_error "Invalid DEST in rule \"$rule\""
|
||||||
|
;;
|
||||||
|
!*)
|
||||||
|
if [ $(list_count $dests) -gt 1 ]; then
|
||||||
|
excludedests=${dests#*!}
|
||||||
|
dests=-
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*!*)
|
||||||
|
excludedests=${dests#*!}
|
||||||
|
dests=${dests%!*}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for source in $(separate_list $sources); do
|
||||||
|
for dest in $(separate_list $dests); do
|
||||||
|
for port in $(separate_list ${ports:=-}); do
|
||||||
|
for sport in $(separate_list ${sports:=-}); do
|
||||||
|
add_a_tc_rule
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
progress_message " TC Rule \"$rule\" $DONE"
|
||||||
|
save_progress_message " TC Rule \"$rule\" Added"
|
||||||
|
}
|
||||||
|
|
||||||
delete_tc1()
|
delete_tc1()
|
||||||
{
|
{
|
||||||
clear_one_tc() {
|
clear_one_tc() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Shorewall 3.2.0 Beta 6
|
Shorewall 3.2.0 Beta 7
|
||||||
|
|
||||||
Note to users upgrading from Shorewall 2.x or 3.0
|
Note to users upgrading from Shorewall 2.x or 3.0
|
||||||
|
|
||||||
@ -27,40 +27,14 @@ Note to users upgrading from Shorewall 2.x or 3.0
|
|||||||
Please see the "Migration Considerations" below for additional upgrade
|
Please see the "Migration Considerations" below for additional upgrade
|
||||||
information.
|
information.
|
||||||
|
|
||||||
Problems Corrected in 3.2.0 Beta 6
|
Problems Corrected in 3.2.0 Beta 7
|
||||||
|
|
||||||
1) Previously, if 'shorewall restart' was done out of an ip-up.local
|
1) Previously, if 'ash' was used as the SHOREWALL_SHELL then any use of
|
||||||
script, some of the utilities like 'tc' and 'ip6tables' were not
|
packet marks would fail.
|
||||||
on the PATH.
|
|
||||||
|
|
||||||
2) In previous 3.2.0 releases, 'detectnets' in /etc/shorewall/interfaces
|
Other changes in 3.2.0 Beta 7
|
||||||
produced an error message:
|
|
||||||
|
|
||||||
ERROR: 'detectnets' not permitted with the -e run-line option
|
1) 'shorewall refresh' once again refreshes the tcrules and traffic shaping.
|
||||||
|
|
||||||
even when the -e option had not been specified.
|
|
||||||
|
|
||||||
3) Previously, the 'proxyarp' option in /etc/shorewall/interfaces caused
|
|
||||||
startup errors.
|
|
||||||
|
|
||||||
4) Previously, specifying specific IP addresses for GATEWAY in with 'balance'
|
|
||||||
/etc/shorewall/providers caused a [re]start error.
|
|
||||||
|
|
||||||
Other changes in 3.2.0 Beta 6
|
|
||||||
|
|
||||||
1) A TOS column has been added to /etc/shorewall/tcrules. This allows marking
|
|
||||||
based on the contents of the TOS field in the packet header.
|
|
||||||
|
|
||||||
2) Beginning with this release, the way in which packet marking in the
|
|
||||||
PREROUTING chain interracts with the 'track' option in /etc/shorewall/providers
|
|
||||||
has changed in two ways:
|
|
||||||
|
|
||||||
a) Packets *arriving* on a tracked interface are now passed to the PREROUTING
|
|
||||||
marking chain so that they may be marked with a mark other than the
|
|
||||||
'track' mark (the connection still retains the 'track' mark).
|
|
||||||
|
|
||||||
b) When HIGH_ROUTE_MARKS=Yes, you can still clear the mark on packets
|
|
||||||
in the PREROUTING chain (i.e., you can specify a mark value of zero).
|
|
||||||
|
|
||||||
Migration Considerations:
|
Migration Considerations:
|
||||||
|
|
||||||
@ -151,11 +125,7 @@ Migration Considerations:
|
|||||||
In no case is it possible to continue a quoted string over multiple lines
|
In no case is it possible to continue a quoted string over multiple lines
|
||||||
without having additional whitespace inserted into the string.
|
without having additional whitespace inserted into the string.
|
||||||
|
|
||||||
6) The "shorewall refresh" command no longer refreshes traffic shaping.
|
6) Beginning with this release, the way in which packet marking in the
|
||||||
Use "shorewall restart" instead if you need to reprocess the
|
|
||||||
tcrules, tcdevices and tcclasses files.
|
|
||||||
|
|
||||||
7) Beginning with this release, the way in which packet marking in the
|
|
||||||
PREROUTING chain interracts with the 'track' option in /etc/shorewall/providers
|
PREROUTING chain interracts with the 'track' option in /etc/shorewall/providers
|
||||||
has changed in two ways:
|
has changed in two ways:
|
||||||
|
|
||||||
@ -550,3 +520,17 @@ New Features:
|
|||||||
d) When you SAVE or RESTORE in tcrules, only the TC mark value is
|
d) When you SAVE or RESTORE in tcrules, only the TC mark value is
|
||||||
saved or restored. Shorewall handles saving and restoring the
|
saved or restored. Shorewall handles saving and restoring the
|
||||||
routing (provider) marks.
|
routing (provider) marks.
|
||||||
|
|
||||||
|
12) A TOS column has been added to /etc/shorewall/tcrules. This allows marking
|
||||||
|
based on the contents of the TOS field in the packet header.
|
||||||
|
|
||||||
|
13) Beginning with this release, the way in which packet marking in the
|
||||||
|
PREROUTING chain interracts with the 'track' option in /etc/shorewall/providers
|
||||||
|
has changed in two ways:
|
||||||
|
|
||||||
|
a) Packets *arriving* on a tracked interface are now passed to the PREROUTING
|
||||||
|
marking chain so that they may be marked with a mark other than the
|
||||||
|
'track' mark (the connection still retains the 'track' mark).
|
||||||
|
|
||||||
|
b) When HIGH_ROUTE_MARKS=Yes, you can still clear the mark on packets
|
||||||
|
in the PREROUTING chain (i.e., you can specify a mark value of zero).
|
||||||
|
Loading…
Reference in New Issue
Block a user