forked from extern/shorewall_code
Modularize dynamic zones and traffic shaping
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@4451 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
4a26e098be
commit
97218564ae
@ -6,11 +6,6 @@
|
||||
#
|
||||
# (c) 1999,2000,2001,2002,2003,2004,2005,2006 - Tom Eastep (teastep@shorewall.net)
|
||||
#
|
||||
# tcstart from tc4shorewall Version 0.5
|
||||
# (c) 2005 Arne Bernin <arne@ucbering.de>
|
||||
# Modified by Tom Eastep for integration into the Shorewall distribution
|
||||
# published under GPL Version 2#
|
||||
#
|
||||
# Complete documentation is available at http://shorewall.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -1861,292 +1856,6 @@ build_exclusion_chain() # $1 = variable to store chain name into $2 = table, $3
|
||||
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 last_device=
|
||||
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_to_kbit $1)
|
||||
echo $(( $rate * ( 128 / $r2q ) ))
|
||||
}
|
||||
|
||||
# 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 dev indent
|
||||
|
||||
dev=$(chain_base $device)
|
||||
|
||||
save_command "if qt ip link ls dev $device; then"
|
||||
indent="$INDENT"
|
||||
INDENT="$INDENT "
|
||||
save_command ${dev}_exists=Yes
|
||||
save_command qt tc qdisc del dev $device root
|
||||
save_command qt tc qdisc del dev $device ingress
|
||||
|
||||
defmark=$(get_defmark_for_dev $device)
|
||||
|
||||
run_tc qdisc add dev $device root handle $devnum: htb default 1$defmark
|
||||
|
||||
save_command "${dev}_mtu=\$(get_device_mtu $device)"
|
||||
run_tc "class add dev $device parent $devnum: classid $devnum:1 htb rate $outband mtu \$${dev}_mtu"
|
||||
|
||||
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 ${dev}_devnum=$devnum
|
||||
devnum=$(($devnum + 1))
|
||||
|
||||
save_progress_message_short " TC Device $tcdev defined."
|
||||
INDENT="$indent"
|
||||
save_command else
|
||||
INDENT="$INDENT "
|
||||
save_command error_message "\"WARNING: Device $device not found -- traffic-shaping configuration skipped\""
|
||||
save_command "${dev}_exists="
|
||||
INDENT="$indent"
|
||||
save_command "fi"
|
||||
save_command
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
add_tc_class() {
|
||||
local full classid tospair tosmask quantum indent
|
||||
|
||||
dev=$(chain_base $device)
|
||||
|
||||
save_command "if [ -n \"\$${dev}_exists\" ] ; then"
|
||||
indent="$INDENT"
|
||||
INDENT="$INDENT "
|
||||
|
||||
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=\$${dev}_devnum
|
||||
#
|
||||
# Convert HEX/OCTAL mark representation to decimal
|
||||
#
|
||||
mark=$(($mark))
|
||||
|
||||
classid=$devnum:1$mark
|
||||
|
||||
[ -n "$devnum" ] || fatal_error "Device $device not defined in $devfile"
|
||||
|
||||
quantum=$(calculate_quantum $rate)
|
||||
|
||||
save_command "[ \$${dev}_mtu -gt $quantum ] && quantum=\$${dev}_mtu || quantum=$quantum"
|
||||
run_tc "class add dev $device parent $devnum:1 classid $classid htb rate $rate ceil $ceil prio $prio mtu \$${dev}_mtu quantum \$quantum"
|
||||
|
||||
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
|
||||
|
||||
save_progress_message_short " TC Class $tcdev defined."
|
||||
INDENT="$indent"
|
||||
save_command fi
|
||||
save_command
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
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; do
|
||||
expandv device inband outband
|
||||
tcdev="$device $inband $outband"
|
||||
add_root_tc && progress_message " 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 " TC Class $tcdev defined."
|
||||
last_device=$device
|
||||
done < $TMP_DIR/tcclasses
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Process a TC Rule - $MARKING_CHAIN is assumed to contain the name of the
|
||||
# default marking chain
|
||||
@ -2551,6 +2260,8 @@ setup_tc1() {
|
||||
save_progress_message "Setting up Traffic Control..."
|
||||
append_file $TC_SCRIPT
|
||||
elif [ -n "$TC_ENABLED" ]; then
|
||||
strip_file_and_lib_load tcdevices tc
|
||||
strip_file_and_lib_load tcclasses tc
|
||||
setup_traffic_shaping
|
||||
fi
|
||||
}
|
||||
|
@ -546,368 +546,6 @@ check_disabled_startup() {
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Add a host or networks to a zone
|
||||
#
|
||||
add_to_zone() # $1...${n-1} = <interface>[:<hosts>] $n = zone
|
||||
{
|
||||
local interface host zone z h z1 z2 chain
|
||||
local dhcp_interfaces blacklist_interfaces maclist_interfaces
|
||||
local tcpflags_interfaces newhostlist=
|
||||
local rulenum source_chain dest_hosts iface hosts hostlist=
|
||||
|
||||
nat_chain_exists() # $1 = chain name
|
||||
{
|
||||
qt $IPTABLES -t nat -L $1 -n
|
||||
}
|
||||
|
||||
do_iptables() # $@ = command
|
||||
{
|
||||
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
|
||||
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
|
||||
|
||||
if ! $IPTABLES $@ ; then
|
||||
error_message "ERROR: Can't add $newhost to zone $zone"
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Load $zones
|
||||
#
|
||||
determine_zones
|
||||
#
|
||||
# Validate Interfaces File
|
||||
#
|
||||
validate_interfaces_file
|
||||
#
|
||||
# Validate Hosts File
|
||||
#
|
||||
validate_hosts_file
|
||||
#
|
||||
# Validate IPSec File
|
||||
#
|
||||
f=$(find_file $IPSECFILE)
|
||||
|
||||
[ -f $f ] && setup_ipsec $f
|
||||
#
|
||||
# Normalize host list
|
||||
#
|
||||
while [ $# -gt 1 ]; do
|
||||
interface=${1%%:*}
|
||||
host=${1#*:}
|
||||
#
|
||||
# Be sure that the interface was dynamic at last [re]start
|
||||
#
|
||||
if ! chain_exists $(input_chain $interface) ; then
|
||||
startup_error "Unknown interface $interface"
|
||||
fi
|
||||
|
||||
if ! chain_exists $(dynamic_in $interface) ; then
|
||||
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
|
||||
fi
|
||||
|
||||
if [ -z "$host" ]; then
|
||||
hostlist="$hostlist $interface:0.0.0.0/0"
|
||||
else
|
||||
for h in $(separate_list $host); do
|
||||
hostlist="$hostlist $interface:$h"
|
||||
done
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
#
|
||||
# Validate Zone
|
||||
#
|
||||
zone=$1
|
||||
|
||||
validate_zone $zone || startup_error "Unknown zone: $zone"
|
||||
|
||||
[ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone"
|
||||
|
||||
#
|
||||
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
||||
#
|
||||
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
||||
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
||||
#
|
||||
# Check for duplicates and create a new zone state file
|
||||
#
|
||||
> ${VARDIR}/zones_$$
|
||||
|
||||
while read z type hosts; do
|
||||
if [ "$z" = "$zone" ]; then
|
||||
for h in $hostlist; do
|
||||
list_search $h $hosts
|
||||
if [ "$?" -gt 0 ]; then
|
||||
newhostlist="$newhostlist $h"
|
||||
else
|
||||
error_message "$h already in zone $zone"
|
||||
fi
|
||||
done
|
||||
|
||||
[ -z "$hosts" ] && hosts=$newhostlist || hosts="$hosts $newhostlist"
|
||||
fi
|
||||
|
||||
eval ${z}_hosts=\"$hosts\"
|
||||
|
||||
echo "$z $type $hosts" >> ${VARDIR}/zones_$$
|
||||
done < ${VARDIR}/zones
|
||||
|
||||
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
||||
|
||||
TERMINATOR=fatal_error
|
||||
#
|
||||
# Create a new Zone state file
|
||||
#
|
||||
for newhost in $newhostlist; do
|
||||
#
|
||||
# Isolate interface and host parts
|
||||
#
|
||||
interface=${newhost%%:*}
|
||||
host=${newhost#*:}
|
||||
#
|
||||
# If the zone passed in the command has a dnat chain then insert a rule in
|
||||
# the nat table PREROUTING chain to jump to that chain when the source
|
||||
# matches the new host(s)#
|
||||
#
|
||||
chain=${zone}_dnat
|
||||
|
||||
if nat_chain_exists $chain; then
|
||||
do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $(match_ipsec_in $zone $newhost) -j $chain
|
||||
fi
|
||||
#
|
||||
# Insert new rules into the filter table for the passed interface
|
||||
#
|
||||
while read z1 z2 chain; do
|
||||
[ "$z1" = "$z2" ] && op="-I" || op="-A"
|
||||
if [ "$z1" = "$zone" ]; then
|
||||
if [ "$z2" = "$FW" ]; then
|
||||
do_iptables $op $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
|
||||
else
|
||||
source_chain=$(dynamic_fwd $interface)
|
||||
if is_ipsec_host $z1 $newhost ; then
|
||||
do_iptables $op $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
|
||||
else
|
||||
eval dest_hosts=\"\$${z2}_hosts\"
|
||||
|
||||
for h in $dest_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
do_iptables $op $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
elif [ "$z2" = "$zone" ]; then
|
||||
if [ "$z1" = "$FW" ]; then
|
||||
#
|
||||
# Add a rule to the dynamic out chain for the interface
|
||||
#
|
||||
do_iptables $op $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
else
|
||||
eval source_hosts=\"\$${z1}_hosts\"
|
||||
|
||||
for h in $source_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
if is_ipsec_host $z1 $h; then
|
||||
do_iptables $op ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
else
|
||||
do_iptables $op $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done < ${VARDIR}/chains
|
||||
|
||||
progress_message "$newhost added to zone $zone"
|
||||
|
||||
done
|
||||
|
||||
rm -rf $TMP_DIR
|
||||
}
|
||||
|
||||
#
|
||||
# Delete a host or networks from a zone
|
||||
#
|
||||
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
|
||||
{
|
||||
local interface host zone z h z1 z2 chain delhost
|
||||
local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
|
||||
local rulenum source_chain dest_hosts iface hosts hostlist=
|
||||
|
||||
#
|
||||
# Load $zones
|
||||
#
|
||||
determine_zones
|
||||
#
|
||||
# Validate Interfaces File
|
||||
#
|
||||
validate_interfaces_file
|
||||
#
|
||||
# Validate Hosts File
|
||||
#
|
||||
validate_hosts_file
|
||||
#
|
||||
# Validate IPSec File
|
||||
#
|
||||
f=$(find_file ipsec)
|
||||
|
||||
[ -f $f ] && setup_ipsec $f
|
||||
|
||||
#
|
||||
# Normalize host list
|
||||
#
|
||||
while [ $# -gt 1 ]; do
|
||||
interface=${1%%:*}
|
||||
host=${1#*:}
|
||||
#
|
||||
# Be sure that the interface was dynamic at last [re]start
|
||||
#
|
||||
if ! chain_exists $(input_chain $interface) ; then
|
||||
startup_error "Unknown interface $interface"
|
||||
fi
|
||||
|
||||
if ! chain_exists $(dynamic_in $interface) ; then
|
||||
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
|
||||
fi
|
||||
|
||||
if [ -z "$host" ]; then
|
||||
hostlist="$hostlist $interface:0.0.0.0/0"
|
||||
else
|
||||
for h in $(separate_list $host); do
|
||||
hostlist="$hostlist $interface:$h"
|
||||
done
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
#
|
||||
# Validate Zone
|
||||
#
|
||||
zone=$1
|
||||
|
||||
validate_zone $zone || startup_error "Unknown zone: $zone"
|
||||
|
||||
[ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
|
||||
|
||||
#
|
||||
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
||||
#
|
||||
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
||||
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
||||
#
|
||||
# Delete the passed hosts from the zone state file
|
||||
#
|
||||
> ${VARDIR}/zones_$$
|
||||
|
||||
while read z hosts; do
|
||||
if [ "$z" = "$zone" ]; then
|
||||
temp=$hosts
|
||||
hosts=
|
||||
|
||||
for host in $hostlist; do
|
||||
found=
|
||||
for h in $temp; do
|
||||
if [ "$h" = "$host" ]; then
|
||||
found=Yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ -n "$found" ] || error_message "WARNING: $host does not appear to be in zone $zone"
|
||||
done
|
||||
|
||||
for h in $temp; do
|
||||
found=
|
||||
for host in $hostlist; do
|
||||
if [ "$h" = "$host" ]; then
|
||||
found=Yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ -n "$found" ] || hosts="$hosts $h"
|
||||
done
|
||||
fi
|
||||
|
||||
eval ${z}_hosts=\"$hosts\"
|
||||
|
||||
echo "$z $hosts" >> ${VARDIR}/zones_$$
|
||||
done < ${VARDIR}/zones
|
||||
|
||||
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
||||
|
||||
TERMINATOR=fatal_error
|
||||
|
||||
for delhost in $hostlist; do
|
||||
interface=${delhost%%:*}
|
||||
host=${delhost#*:}
|
||||
#
|
||||
# Delete any nat table entries for the host(s)
|
||||
#
|
||||
qt_iptables -t nat -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $zone $delhost) -j ${zone}_dnat
|
||||
#
|
||||
# Delete rules rules the input chains for the passed interface
|
||||
#
|
||||
while read z1 z2 chain; do
|
||||
if [ "$z1" = "$zone" ]; then
|
||||
if [ "$z2" = "$FW" ]; then
|
||||
qt_iptables -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $delhost) -j $chain
|
||||
else
|
||||
source_chain=$(dynamic_fwd $interface)
|
||||
if is_ipsec_host $z1 $delhost ; then
|
||||
qt_iptables -D $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
|
||||
else
|
||||
eval dest_hosts=\"\$${z2}_hosts\"
|
||||
|
||||
[ "$z2" = "$zone" ] && dest_hosts="$dest_hosts $hostlist"
|
||||
|
||||
for h in $dest_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
qt_iptables -D $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
elif [ "$z2" = "$zone" ]; then
|
||||
if [ "$z1" = "$FW" ]; then
|
||||
qt_iptables -D $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
else
|
||||
eval source_hosts=\"\$${z1}_hosts\"
|
||||
|
||||
for h in $source_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
if is_ipsec_host $z1 $h; then
|
||||
qt_iptables -D ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
else
|
||||
qt_iptables -D $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done < ${VARDIR}/chains
|
||||
|
||||
progress_message "$delhost removed from zone $zone"
|
||||
|
||||
done
|
||||
|
||||
rm -rf $TMP_DIR
|
||||
}
|
||||
|
||||
#
|
||||
# Give Usage Information
|
||||
#
|
||||
@ -995,6 +633,7 @@ case "$COMMAND" in
|
||||
add)
|
||||
[ $# -lt 3 ] && usage
|
||||
do_initialize
|
||||
lib_load dynamiczones "The add command"
|
||||
my_mutex_on
|
||||
if ! shorewall_is_started ; then
|
||||
echo "Shorewall Not Started"
|
||||
@ -1009,6 +648,7 @@ case "$COMMAND" in
|
||||
|
||||
delete)
|
||||
[ $# -lt 3 ] && usage
|
||||
lib_load dynamiczones "The delete command"
|
||||
do_initialize
|
||||
my_mutex_on
|
||||
if ! shorewall_is_started ; then
|
||||
|
@ -1770,11 +1770,13 @@ lib_avail() # $1 = Name of the Library
|
||||
[ -f ${SHAREDIR}/lib.$1 ]
|
||||
}
|
||||
|
||||
strip_file_and_lib_load() # $1 = logical file name, $3 = Error message heading if the library cannot be found
|
||||
strip_file_and_lib_load() # $1 = logical file name, $2 = library to load if the stripped file is non-empty
|
||||
{
|
||||
strip_file $1
|
||||
local f=$(find_file $1)
|
||||
|
||||
[ -s $TMP_DIR/$1 ] && lib_load $2 "$3"
|
||||
strip_file $1 $f
|
||||
|
||||
[ -s $TMP_DIR/$1 ] && lib_load $2 "A non-empty $1 file ($f)"
|
||||
}
|
||||
|
||||
#
|
||||
@ -1785,7 +1787,6 @@ strip_file_and_lib_load() # $1 = logical file name, $3 = Error message heading i
|
||||
|
||||
LEFTSHIFT='<<'
|
||||
|
||||
|
||||
#
|
||||
# Convert an IP address in dot quad format to an integer
|
||||
#
|
||||
@ -3073,8 +3074,13 @@ do_initialize() {
|
||||
BLACKLISTNEWONLY=$(added_param_value_no BLACKLISTNEWONLY $BLACKLISTNEWONLY)
|
||||
DISABLE_IPV6=$(added_param_value_no DISABLE_IPV6 $DISABLE_IPV6)
|
||||
BRIDGING=$(added_param_value_no BRIDGING $BRIDGING)
|
||||
|
||||
DYNAMIC_ZONES=$(added_param_value_no DYNAMIC_ZONES $DYNAMIC_ZONES)
|
||||
[ -n "$DYNAMIC_ZONES" -a -n "$EXPORT" ] && fatal_error "DYNAMIC_ZONES=Yes is incompatible with the -e option"
|
||||
if [ -n "$DYNAMIC_ZONES" ]; then
|
||||
[ -n "$EXPORT" ] && fatal_error "DYNAMIC_ZONES=Yes is incompatible with the -e option"
|
||||
lib_avail dynamiczones || error_message "WARNING: DYNAMIC_ZONES=Yes requires the Shorewall dynamiczones library (${SHAREDIR}/lib.dynamiczones) which is not installed"
|
||||
fi
|
||||
|
||||
STARTUP_ENABLED=$(added_param_value_yes STARTUP_ENABLED $STARTUP_ENABLED)
|
||||
RETAIN_ALIASES=$(added_param_value_no RETAIN_ALIASES $RETAIN_ALIASES)
|
||||
[ -n "${ADD_IP_ALIASES}${ADD_SNAT_ALIASES}" ] || RETAIN_ALIASES=
|
||||
|
@ -647,6 +647,15 @@ for f in macro.* ; do
|
||||
echo "Macro ${f#*.} file installed as ${PREFIX}/usr/share/shorewall/$f"
|
||||
done
|
||||
#
|
||||
# Install the libraries
|
||||
#
|
||||
for f in lib.* ; do
|
||||
if [ -f $f ]; then
|
||||
install_file $f ${PREFIX}/usr/share/shorewall/$f 0644
|
||||
echo "Macro ${f#*.} file installed as ${PREFIX}/usr/share/shorewall/$f"
|
||||
fi
|
||||
done
|
||||
#
|
||||
# Install the program skeleton files
|
||||
#
|
||||
for f in prog.* ; do
|
||||
|
@ -6,11 +6,6 @@
|
||||
#
|
||||
# (c) 1999,2000,2001,2002,2003,2004,2005,2006 - Tom Eastep (teastep@shorewall.net)
|
||||
#
|
||||
# tcstart from tc4shorewall Version 0.5
|
||||
# (c) 2005 Arne Bernin <arne@ucbering.de>
|
||||
# Modified by Tom Eastep for integration into the Shorewall distribution
|
||||
# published under GPL Version 2#
|
||||
#
|
||||
# Complete documentation is available at http://shorewall.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -26,3 +21,364 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
||||
|
||||
#
|
||||
# Add a host or networks to a zone
|
||||
#
|
||||
add_to_zone() # $1...${n-1} = <interface>[:<hosts>] $n = zone
|
||||
{
|
||||
local interface host zone z h z1 z2 chain
|
||||
local dhcp_interfaces blacklist_interfaces maclist_interfaces
|
||||
local tcpflags_interfaces newhostlist=
|
||||
local rulenum source_chain dest_hosts iface hosts hostlist=
|
||||
|
||||
nat_chain_exists() # $1 = chain name
|
||||
{
|
||||
qt $IPTABLES -t nat -L $1 -n
|
||||
}
|
||||
|
||||
do_iptables() # $@ = command
|
||||
{
|
||||
[ -n "$BRIDGING" ] && [ -f $TMP_DIR/physdev ] && rm -f $TMP_DIR/physdev
|
||||
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
|
||||
|
||||
if ! $IPTABLES $@ ; then
|
||||
error_message "ERROR: Can't add $newhost to zone $zone"
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Load $zones
|
||||
#
|
||||
determine_zones
|
||||
#
|
||||
# Validate Interfaces File
|
||||
#
|
||||
validate_interfaces_file
|
||||
#
|
||||
# Validate Hosts File
|
||||
#
|
||||
validate_hosts_file
|
||||
#
|
||||
# Validate IPSec File
|
||||
#
|
||||
f=$(find_file $IPSECFILE)
|
||||
|
||||
[ -f $f ] && setup_ipsec $f
|
||||
#
|
||||
# Normalize host list
|
||||
#
|
||||
while [ $# -gt 1 ]; do
|
||||
interface=${1%%:*}
|
||||
host=${1#*:}
|
||||
#
|
||||
# Be sure that the interface was dynamic at last [re]start
|
||||
#
|
||||
if ! chain_exists $(input_chain $interface) ; then
|
||||
startup_error "Unknown interface $interface"
|
||||
fi
|
||||
|
||||
if ! chain_exists $(dynamic_in $interface) ; then
|
||||
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
|
||||
fi
|
||||
|
||||
if [ -z "$host" ]; then
|
||||
hostlist="$hostlist $interface:0.0.0.0/0"
|
||||
else
|
||||
for h in $(separate_list $host); do
|
||||
hostlist="$hostlist $interface:$h"
|
||||
done
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
#
|
||||
# Validate Zone
|
||||
#
|
||||
zone=$1
|
||||
|
||||
validate_zone $zone || startup_error "Unknown zone: $zone"
|
||||
|
||||
[ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone"
|
||||
|
||||
#
|
||||
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
||||
#
|
||||
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
||||
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
||||
#
|
||||
# Check for duplicates and create a new zone state file
|
||||
#
|
||||
> ${VARDIR}/zones_$$
|
||||
|
||||
while read z type hosts; do
|
||||
if [ "$z" = "$zone" ]; then
|
||||
for h in $hostlist; do
|
||||
list_search $h $hosts
|
||||
if [ "$?" -gt 0 ]; then
|
||||
newhostlist="$newhostlist $h"
|
||||
else
|
||||
error_message "$h already in zone $zone"
|
||||
fi
|
||||
done
|
||||
|
||||
[ -z "$hosts" ] && hosts=$newhostlist || hosts="$hosts $newhostlist"
|
||||
fi
|
||||
|
||||
eval ${z}_hosts=\"$hosts\"
|
||||
|
||||
echo "$z $type $hosts" >> ${VARDIR}/zones_$$
|
||||
done < ${VARDIR}/zones
|
||||
|
||||
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
||||
|
||||
TERMINATOR=fatal_error
|
||||
#
|
||||
# Create a new Zone state file
|
||||
#
|
||||
for newhost in $newhostlist; do
|
||||
#
|
||||
# Isolate interface and host parts
|
||||
#
|
||||
interface=${newhost%%:*}
|
||||
host=${newhost#*:}
|
||||
#
|
||||
# If the zone passed in the command has a dnat chain then insert a rule in
|
||||
# the nat table PREROUTING chain to jump to that chain when the source
|
||||
# matches the new host(s)#
|
||||
#
|
||||
chain=${zone}_dnat
|
||||
|
||||
if nat_chain_exists $chain; then
|
||||
do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $(match_ipsec_in $zone $newhost) -j $chain
|
||||
fi
|
||||
#
|
||||
# Insert new rules into the filter table for the passed interface
|
||||
#
|
||||
while read z1 z2 chain; do
|
||||
[ "$z1" = "$z2" ] && op="-I" || op="-A"
|
||||
if [ "$z1" = "$zone" ]; then
|
||||
if [ "$z2" = "$FW" ]; then
|
||||
do_iptables $op $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
|
||||
else
|
||||
source_chain=$(dynamic_fwd $interface)
|
||||
if is_ipsec_host $z1 $newhost ; then
|
||||
do_iptables $op $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
|
||||
else
|
||||
eval dest_hosts=\"\$${z2}_hosts\"
|
||||
|
||||
for h in $dest_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
do_iptables $op $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
elif [ "$z2" = "$zone" ]; then
|
||||
if [ "$z1" = "$FW" ]; then
|
||||
#
|
||||
# Add a rule to the dynamic out chain for the interface
|
||||
#
|
||||
do_iptables $op $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
else
|
||||
eval source_hosts=\"\$${z1}_hosts\"
|
||||
|
||||
for h in $source_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
if is_ipsec_host $z1 $h; then
|
||||
do_iptables $op ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
else
|
||||
do_iptables $op $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done < ${VARDIR}/chains
|
||||
|
||||
progress_message "$newhost added to zone $zone"
|
||||
|
||||
done
|
||||
|
||||
rm -rf $TMP_DIR
|
||||
}
|
||||
|
||||
#
|
||||
# Delete a host or networks from a zone
|
||||
#
|
||||
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
|
||||
{
|
||||
local interface host zone z h z1 z2 chain delhost
|
||||
local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
|
||||
local rulenum source_chain dest_hosts iface hosts hostlist=
|
||||
|
||||
#
|
||||
# Load $zones
|
||||
#
|
||||
determine_zones
|
||||
#
|
||||
# Validate Interfaces File
|
||||
#
|
||||
validate_interfaces_file
|
||||
#
|
||||
# Validate Hosts File
|
||||
#
|
||||
validate_hosts_file
|
||||
#
|
||||
# Validate IPSec File
|
||||
#
|
||||
f=$(find_file ipsec)
|
||||
|
||||
[ -f $f ] && setup_ipsec $f
|
||||
|
||||
#
|
||||
# Normalize host list
|
||||
#
|
||||
while [ $# -gt 1 ]; do
|
||||
interface=${1%%:*}
|
||||
host=${1#*:}
|
||||
#
|
||||
# Be sure that the interface was dynamic at last [re]start
|
||||
#
|
||||
if ! chain_exists $(input_chain $interface) ; then
|
||||
startup_error "Unknown interface $interface"
|
||||
fi
|
||||
|
||||
if ! chain_exists $(dynamic_in $interface) ; then
|
||||
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
|
||||
fi
|
||||
|
||||
if [ -z "$host" ]; then
|
||||
hostlist="$hostlist $interface:0.0.0.0/0"
|
||||
else
|
||||
for h in $(separate_list $host); do
|
||||
hostlist="$hostlist $interface:$h"
|
||||
done
|
||||
fi
|
||||
|
||||
shift
|
||||
done
|
||||
#
|
||||
# Validate Zone
|
||||
#
|
||||
zone=$1
|
||||
|
||||
validate_zone $zone || startup_error "Unknown zone: $zone"
|
||||
|
||||
[ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
|
||||
|
||||
#
|
||||
# Be sure that Shorewall has been restarted using a DZ-aware version of the code
|
||||
#
|
||||
[ -f ${VARDIR}/chains ] || startup_error "${VARDIR}/chains -- file not found"
|
||||
[ -f ${VARDIR}/zones ] || startup_error "${VARDIR}/zones -- file not found"
|
||||
#
|
||||
# Delete the passed hosts from the zone state file
|
||||
#
|
||||
> ${VARDIR}/zones_$$
|
||||
|
||||
while read z hosts; do
|
||||
if [ "$z" = "$zone" ]; then
|
||||
temp=$hosts
|
||||
hosts=
|
||||
|
||||
for host in $hostlist; do
|
||||
found=
|
||||
for h in $temp; do
|
||||
if [ "$h" = "$host" ]; then
|
||||
found=Yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ -n "$found" ] || error_message "WARNING: $host does not appear to be in zone $zone"
|
||||
done
|
||||
|
||||
for h in $temp; do
|
||||
found=
|
||||
for host in $hostlist; do
|
||||
if [ "$h" = "$host" ]; then
|
||||
found=Yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
[ -n "$found" ] || hosts="$hosts $h"
|
||||
done
|
||||
fi
|
||||
|
||||
eval ${z}_hosts=\"$hosts\"
|
||||
|
||||
echo "$z $hosts" >> ${VARDIR}/zones_$$
|
||||
done < ${VARDIR}/zones
|
||||
|
||||
mv -f ${VARDIR}/zones_$$ ${VARDIR}/zones
|
||||
|
||||
TERMINATOR=fatal_error
|
||||
|
||||
for delhost in $hostlist; do
|
||||
interface=${delhost%%:*}
|
||||
host=${delhost#*:}
|
||||
#
|
||||
# Delete any nat table entries for the host(s)
|
||||
#
|
||||
qt_iptables -t nat -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $zone $delhost) -j ${zone}_dnat
|
||||
#
|
||||
# Delete rules rules the input chains for the passed interface
|
||||
#
|
||||
while read z1 z2 chain; do
|
||||
if [ "$z1" = "$zone" ]; then
|
||||
if [ "$z2" = "$FW" ]; then
|
||||
qt_iptables -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $delhost) -j $chain
|
||||
else
|
||||
source_chain=$(dynamic_fwd $interface)
|
||||
if is_ipsec_host $z1 $delhost ; then
|
||||
qt_iptables -D $source_chain $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j ${z1}_frwd
|
||||
else
|
||||
eval dest_hosts=\"\$${z2}_hosts\"
|
||||
|
||||
[ "$z2" = "$zone" ] && dest_hosts="$dest_hosts $hostlist"
|
||||
|
||||
for h in $dest_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
qt_iptables -D $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
elif [ "$z2" = "$zone" ]; then
|
||||
if [ "$z1" = "$FW" ]; then
|
||||
qt_iptables -D $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
else
|
||||
eval source_hosts=\"\$${z1}_hosts\"
|
||||
|
||||
for h in $source_hosts; do
|
||||
iface=${h%%:*}
|
||||
hosts=${h#*:}
|
||||
|
||||
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
|
||||
if is_ipsec_host $z1 $h; then
|
||||
qt_iptables -D ${z1}_dyn -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
else
|
||||
qt_iptables -D $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done < ${VARDIR}/chains
|
||||
|
||||
progress_message "$delhost removed from zone $zone"
|
||||
|
||||
done
|
||||
|
||||
rm -rf $TMP_DIR
|
||||
}
|
||||
|
310
Shorewall/lib.tc
Normal file
310
Shorewall/lib.tc
Normal file
@ -0,0 +1,310 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Shorewall 3.2 -- /usr/share/shorewall/lib.tc
|
||||
#
|
||||
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
||||
#
|
||||
# (c) 1999,2000,2001,2002,2003,2004,2005,2006 - Tom Eastep (teastep@shorewall.net)
|
||||
#
|
||||
# tcstart from tc4shorewall Version 0.5
|
||||
# (c) 2005 Arne Bernin <arne@ucbering.de>
|
||||
# Modified by Tom Eastep for integration into the Shorewall distribution
|
||||
# published under GPL Version 2#
|
||||
#
|
||||
# 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
|
||||
|
||||
#
|
||||
# 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 last_device=
|
||||
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_to_kbit $1)
|
||||
echo $(( $rate * ( 128 / $r2q ) ))
|
||||
}
|
||||
|
||||
# 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 dev indent
|
||||
|
||||
dev=$(chain_base $device)
|
||||
|
||||
save_command "if qt ip link ls dev $device; then"
|
||||
indent="$INDENT"
|
||||
INDENT="$INDENT "
|
||||
save_command ${dev}_exists=Yes
|
||||
save_command qt tc qdisc del dev $device root
|
||||
save_command qt tc qdisc del dev $device ingress
|
||||
|
||||
defmark=$(get_defmark_for_dev $device)
|
||||
|
||||
run_tc qdisc add dev $device root handle $devnum: htb default 1$defmark
|
||||
|
||||
save_command "${dev}_mtu=\$(get_device_mtu $device)"
|
||||
run_tc "class add dev $device parent $devnum: classid $devnum:1 htb rate $outband mtu \$${dev}_mtu"
|
||||
|
||||
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 ${dev}_devnum=$devnum
|
||||
devnum=$(($devnum + 1))
|
||||
|
||||
save_progress_message_short " TC Device $tcdev defined."
|
||||
INDENT="$indent"
|
||||
save_command else
|
||||
INDENT="$INDENT "
|
||||
save_command error_message "\"WARNING: Device $device not found -- traffic-shaping configuration skipped\""
|
||||
save_command "${dev}_exists="
|
||||
INDENT="$indent"
|
||||
save_command "fi"
|
||||
save_command
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
add_tc_class() {
|
||||
local full classid tospair tosmask quantum indent
|
||||
|
||||
dev=$(chain_base $device)
|
||||
|
||||
save_command "if [ -n \"\$${dev}_exists\" ] ; then"
|
||||
indent="$INDENT"
|
||||
INDENT="$INDENT "
|
||||
|
||||
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=\$${dev}_devnum
|
||||
#
|
||||
# Convert HEX/OCTAL mark representation to decimal
|
||||
#
|
||||
mark=$(($mark))
|
||||
|
||||
classid=$devnum:1$mark
|
||||
|
||||
[ -n "$devnum" ] || fatal_error "Device $device not defined in $devfile"
|
||||
|
||||
quantum=$(calculate_quantum $rate)
|
||||
|
||||
save_command "[ \$${dev}_mtu -gt $quantum ] && quantum=\$${dev}_mtu || quantum=$quantum"
|
||||
run_tc "class add dev $device parent $devnum:1 classid $classid htb rate $rate ceil $ceil prio $prio mtu \$${dev}_mtu quantum \$quantum"
|
||||
|
||||
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
|
||||
|
||||
save_progress_message_short " TC Class $tcdev defined."
|
||||
INDENT="$indent"
|
||||
save_command fi
|
||||
save_command
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
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; do
|
||||
expandv device inband outband
|
||||
tcdev="$device $inband $outband"
|
||||
add_root_tc && progress_message " 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 " TC Class $tcdev defined."
|
||||
last_device=$device
|
||||
done < $TMP_DIR/tcclasses
|
||||
fi
|
||||
}
|
@ -115,6 +115,8 @@ fi
|
||||
%attr(0555,root,root) /usr/share/shorewall/firewall
|
||||
%attr(0555,root,root) /usr/share/shorewall/help
|
||||
%attr(0644,root,root) /usr/share/shorewall/Limit
|
||||
%attr(0444,root,root) /usr/share/shorewall/lib.dynamiczones
|
||||
%attr(0444,root,root) /usr/share/shorewall/lib.tc
|
||||
%attr(0644,root,root) /usr/share/shorewall/macro.AllowICMPs
|
||||
%attr(0644,root,root) /usr/share/shorewall/macro.Amanda
|
||||
%attr(0644,root,root) /usr/share/shorewall/macro.Auth
|
||||
|
Loading…
Reference in New Issue
Block a user