#! /bin/bash
# Firewall nove generace pro Czela Debian 3.0
# Autor: Mirek Slugen
# Spoluatori: Michal Perlik, Michal Vondracek, Jan Chmelensky
# Vytvoreno: 06.11.2006
# Naposledy zmeneno: 08.03.2009
# Tento skript muzete volne sirit a upravovat.
# implementace QoSu
qos_start() {
# Před každým spuštěním QoSu musíme předchozí QoS ukončit, raději i pokud nebyl aktivní
qos_stop
echo "Starting QoS..."
# lokální proměnné
local I=""
local J=""
local QOS=""
local DEV=""
local DEV_2=""
local RATE=""
local DUPLEX=""
local DIRECTION=""
local COUNT="0"
local DEVS=""
local RATES=""
local DUPLEXS=""
local DIRECTIONS=""
local CLASS=""
local CLASS_DEV=""
local CLASS_MIN=""
local CLASS_MAX=""
local CLASSES=""
local RATE_MIN=""
# Zjistime rozhrani, na kterych chceme mit spusteny QoS
I="0"
while [ "$I" -lt 20 ]; do
DEV=DEV${I}_IFACE
DEV=${!DEV}
QOS=DEV${I}_QOS
QOS=${!QOS}
RATE=DEV${I}_QOS_RATE
RATE=${!RATE}
DUPLEX=DEV${I}_QOS_DUPLEX
DUPLEX=${!DUPLEX}
DIRECTION=DEV${I}_QOS_DIRECTION
DIRECTION=${!DIRECTION}
# inkrementujeme před continue
((I++))
[ "$DEV" == "" ] && continue
[ "$QOS" != "yes" ] && continue
[ "$RATE" == "" ] && continue
[ "$DUPLEX" == "" ] && continue
[ "$DIRECTION" == "" ] && continue
DEVS[$COUNT]="$DEV"
RATES[$COUNT]="$RATE"
DUPLEXES[$COUNT]="$DUPLEX"
DIRECTIONS[$COUNT]="$DIRECTION"
((COUNT++))
done
# skončíme pokud nejsou rozhraní na kterých bychom QoS spustili
if [ "$COUNT" -lt "1" ]; then
echo "there is no QoS interface!"
return 0
fi
# Zavedeni modulu pro imq a ifb , v nové verzi už není třeba modul znovu zavádět, v kernelu 2.6.26
# a vyšším je problém s odstraněním modulu z paměti (rmmod), jednoduchý test problému:
# modprobe imq
# iptables -t mangle -A PREROUTING -i eth0 -j IMQ --todev 0
# ip link set imq0 up
# sleep 5
# ping www.seznam.cz -c 2
# iptables -t mangle -F
# ip link set imq0 down
# sleep 0.5
# rmmod imq
#
# Proto zavedeme imq a ifb s maximálním množstvím zařízení abychom ho nemuseli při změně počtu
# zařízení znovu zavádět. Nezavádíme imq modul, pokud už je zaveden!
if [ "$QOS_DEVICE" == "imq" ]; then
[ "`lsmod | awk '{print \$1}' | grep -x \"imq\"`" == "" ] && modprobe imq numdevs=16 &>/dev/null
elif [ "$QOS_DEVICE" == "ifb" ]; then
[ "`lsmod | awk '{print \$1}' | grep -x \"ifb\"`" == "" ] && modprobe ifb numifbs=16 &>/dev/null
fi
# Nahození příslušních rozhraní, pro fungovaní QoSu je potřeba rozhraní nahodit
if [ "$QOS_DEVICE" == "imq" ] || [ "$QOS_DEVICE" == "ifb" ]; then
I="0"
while [ "$I" -lt "$COUNT" ]; do
$IP link set ${QOS_DEVICE}$I up
((I++))
done
fi
# Na získaná rozhraní nasadíme QoS
I="0"
for DEV in ${DEVS[@]}; do
RATE="${RATES[$I]}"
DIRECTION="${DIRECTIONS[$I]}"
DUPLEX="${DUPLEXES[$I]}"
# Kontrola na minimální rychlost rozhraní
if [ "$RATE" -lt 10 ]; then
echo "Rate on $DEV is too small!"
((I++))
continue
fi
# Pro HTB vypočítáme R2Q
if [ "$QOS_LIMIT_TYPE" == "htb" ]; then
if [ "$RATE" -lt 20 ]; then
echo "Rate on $DEV is too small for HTB R2Q, try set QOS_LIMIT_TYPE to HFSC!"
R2Q="1"
elif [ "$RATE" -lt 100 ]; then
R2Q="1"
else
R2Q="$[$RATE/100]"
fi
fi
# speciální garantované třídy
CLASSES=""
RATE_MIN="0"
J="1"
while true; do
CLASS_DEV=CLASS_${J}_DEV
CLASS_DEV=${!CLASS_DEV}
[ "$CLASS_DEV" == "" ] && break
if [ "$CLASS_DEV" != "$DEV" ] && [ "$CLASS_DEV" != "all" ]; then
((J++))
continue
fi
CLASS_MIN=CLASS_${J}_MIN
CLASS_MIN=${!CLASS_MIN}
CLASS_MAX=CLASS_${J}_MAX
CLASS_MAX=${!CLASS_MAX}
# garantovaná rychlost nemůže být větší než maximální rychlost na rozhraní
if [ "$CLASS_MIN" -ge "$RATE" ]; then
((J++))
continue
fi
CLASSES=$CLASSES"$J $CLASS_MIN $CLASS_MAX
"
RATE_MIN=$(($RATE_MIN + $CLASS_MIN))
((J++))
done
# kontrola na překročení maximální rychlosti rozhraní, potřebujeme alespoň 10 kbitů navíc
if [ "$(($RATE - $RATE_MIN))" -lt "10" ]; then
echo "Byla vypoctena pozadovana garantovana rychlost $RATE_MIN, garantovana rychlost na"
echo "rozhrani $DEV muze byt maximalne $(($RATE - 10)), snizte garantovane rychlosti,"
echo "nebo nastavte garantovane tridy na konkretni rozhrani, misto rozhrani \"all\"."
echo ""
echo "Garantovane tridy pro rozhrani $DEV budou vynechany!"
echo ""
CLASSES=""
fi
# Pomocná rozhraní jako IFB a IMQ
if [ "$QOS_DEVICE" != "" ]; then
DEV_2="${QOS_DEVICE}$I"
echo " $DEV rate ${RATE} kbit/s with $DEV_2 type $DUPLEX"
if [ "$QOS_DEVICE" == "imq" ]; then
if [ "$DUPLEX" == "HD" ]; then
if [ "$DUMMY_IFACE" != "" ]; then
[ "$DUMMY_IP" == "" ] && DUMMY_IP="`$IP addr show $DUMMY_IFACE | grep inet | grep -v inet6 | awk '{print \$2}' | cut -d \"/\" -f1`"
$IPTABLES -t mangle -A POSTROUTING -o $DEV -s ! $DUMMY_IP -j IMQ --todev $I
else
$IPTABLES -t mangle -A POSTROUTING -o $DEV -j IMQ --todev $I
fi
$IPTABLES -t mangle -A PREROUTING -i $DEV -j IMQ --todev $I
DEV=""
else
$IPTABLES -t mangle -A PREROUTING -i $DEV -j IMQ --todev $I
fi
elif [ "$QOS_DEVICE" == "ifb" ]; then
# IFB neumí poloviční duplex
[ "$DUPLEX" == "HD" ] && echo "IFB does not support HD (half duplex), using FD (full duplex)!"
# Kontrola na název rozhraní ath, které indikuje atheros kartu, ta má problémy s IFB
if [ "${DEV:0:3}" == "ath" ]; then
# Test, jestli dojde ke kernel panicu na atheros kartách:
#modprobe ifb
#ip link set ifb0 up
#tc qdisc add dev ath0 ingress
#tc filter add dev ath0 parent ffff: protocol ip prio 10 u32 match u32 0 0 flowid 1:0 action mirred egress redirect dev ifb0
echo "IFB on atheros (madwifi) cards could cause kernel panic, try to use IMQ, or"
echo "disable QoS on atheros cards!"
DEV_2=""
else
$TC qdisc add dev $DEV ingress
$TC filter add dev $DEV parent ffff: protocol ip prio 10 u32 match u32 0 0 flowid 1:0 action mirred egress redirect dev $DEV_2
fi
fi
else
echo " $DEV rate ${RATE} kbit/s without ifb or imq"
DEV_2=""
fi
# Na základním i pomocném rozhraní nasadíme QoS
for DEV in $DEV $DEV_2; do
# QoS pro esfq, nebo sfq
if [ "$QOS_TYPE" == "esfq" ] || [ "$QOS_TYPE" == "layer7_esfq" ]; then
# Pro ESFQ musíme určit na základě typu rozhraní hash
if [ "$DIRECTION" == "WAN" ]; then
if [ "${DEV:0:3}" != "imq" ] && [ "${DEV:0:3}" != "ifb" ]; then
SFQ="esfq perturb 10 hash src"
else
SFQ="esfq perturb 10 hash dst"
fi
elif [ "$DIRECTION" == "NAT" ]; then
if [ "${DEV:0:3}" != "imq" ] && [ "${DEV:0:3}" != "ifb" ]; then
SFQ="esfq perturb 10 hash ctnatchg"
else
SFQ="esfq perturb 10 hash dst"
fi
else
if [ "${DEV:0:3}" != "imq" ] && [ "${DEV:0:3}" != "ifb" ]; then
SFQ="esfq perturb 10 hash dst"
else
SFQ="esfq perturb 10 hash src"
fi
fi
else
SFQ="sfq perturb 10"
fi
# Základní nasazení tříd je pro všechny typy QoSu stejné
# Vytvoříme root qdisc
$TC qdisc add dev $DEV root handle 1:0 prio bands 3 priomap 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2
# V prvních dvou třídách nebudeme limitovat, pouze budeme rozdělovat pásmo pomocí sfq
$TC qdisc add dev $DEV parent 1:1 handle 11:0 $SFQ
$TC qdisc add dev $DEV parent 1:2 handle 12:0 $SFQ
# Omarkované pakety roztřídíme do jednotlivých tříd, první třída bude mít prioritu 1,
# tj. cokoliv co do ní přejde už nezávisle na dalších pravidlech zpracuje, ostatní
# nemají prioritu udanou, tím se řadí na konec až za všechna ostatní pravidla.
$TC filter add dev $DEV parent 1:0 protocol ip prio 1 handle 1 fw flowid 1:1
$TC filter add dev $DEV parent 1:0 protocol ip handle 2 fw flowid 1:2
# 3. třída je určena pro datového omezení
if [ "$QOS_LIMIT_TYPE" == "htb" ]; then
$TC qdisc add dev $DEV parent 1:3 handle 13:0 htb r2q $R2Q default 111
# Zakladni htb tride dame plnou rychlost, dalsi budou mit rychlost sdilenou HTTP,mail, DC++,
$TC class add dev $DEV parent 13:0 classid 13:1 htb rate ${RATE}kbit
else
$TC qdisc add dev $DEV parent 1:3 handle 13:0 hfsc default 111
# Zakladni hfsc tride dame plnou rychlost, dalsi budou mit rychlost sdilenou HTTP,mail, DC++,
$TC class add dev $DEV parent 13:0 classid 13:1 hfsc ls m2 ${RATE}kbit ul m2 ${RATE}kbit
fi
# Pokročilé nasazení tříd podle typu
if [ "$QOS_TYPE" == "layer7" ] || [ "$QOS_TYPE" == "layer7_esfq" ]; then
if [ "$QOS_LIMIT_TYPE" == "htb" ]; then
$TC class add dev $DEV parent 13:1 classid 13:111 htb rate $[5*($RATE - $RATE_MIN)/10]kbit ceil ${RATE}kbit
$TC class add dev $DEV parent 13:1 classid 13:112 htb rate $[3*($RATE - $RATE_MIN)/10]kbit ceil ${RATE}kbit
$TC class add dev $DEV parent 13:1 classid 13:113 htb rate $[2*($RATE - $RATE_MIN)/10]kbit ceil ${RATE}kbit
else
$TC class add dev $DEV parent 13:1 classid 13:111 hfsc ls m2 $[5*($RATE - $RATE_MIN)/10]kbit ul m2 ${RATE}kbit
$TC class add dev $DEV parent 13:1 classid 13:112 hfsc ls m2 $[3*($RATE - $RATE_MIN)/10]kbit ul m2 ${RATE}kbit
$TC class add dev $DEV parent 13:1 classid 13:113 hfsc ls m2 $[2*($RATE - $RATE_MIN)/10]kbit ul m2 ${RATE}kbit
fi
# V kazde tride jeste pouziji sfq
$TC qdisc add dev $DEV parent 13:111 handle 111:0 $SFQ
$TC qdisc add dev $DEV parent 13:112 handle 112:0 $SFQ
$TC qdisc add dev $DEV parent 13:113 handle 113:0 $SFQ
# Další třídy zpracovávající pravidla z iptables
$TC filter add dev $DEV parent 13:0 protocol ip handle 3 fw flowid 13:111
$TC filter add dev $DEV parent 13:0 protocol ip handle 4 fw flowid 13:112
$TC filter add dev $DEV parent 13:0 protocol ip handle 5 fw flowid 13:113
else
# Nastavime maximalni ryhlost pro vse co jde do tridy 2 (3. skupina)
if [ "$QOS_LIMIT_TYPE" == "htb" ]; then
$TC class add dev $DEV parent 13:1 classid 13:111 htb rate $[($RATE - $RATE_MIN)]kbit ceil ${RATE}kbit
else
# Zakladni hfsc tride dame plnou rychlost
$TC class add dev $DEV parent 13:1 classid 13:111 hfsc ls m2 $[($RATE - $RATE_MIN)]kbit ul m2 ${RATE}kbit
fi
# V kazde tride jeste pouziji sfq
$TC qdisc add dev $DEV parent 13:111 handle 111:0 $SFQ
# I pokud nepoužíváme layer7, můžeme využít markování pomocí iptables
$TC filter add dev $DEV parent 13:0 protocol ip handle 3 fw flowid 13:111
fi
# speciální třídy
IFS=$'\t\n'
for CLASS in $CLASSES; do
IFS=$' \t\n'
CLASS=( $CLASS )
# garantovaná rychlost nemůže být větší než maximální rychlost na rozhraní
[ "${CLASS[1]}" -ge "$RATE" ] && continue
# pokud není zadaná maximální rychlost, tak je maximum celkový rychlost rozhraní
[ "${CLASS[2]}" == "" ] && CLASS[2]=$RATE
# pokud je maximální rychlost menší než minimální, tak je maximum rychlost rozhraní
[ "${CLASS[2]}" -lt "${CLASS[1]}" ] && CLASS[2]=$RATE
# pokud je maximální rychlost větší, než maximální rychlost rozhraní, tak je maximum rychlost rozhraní
[ "${CLASS[2]}" -gt "$RATE" ] && CLASS[2]=$RATE
if [ "$QOS_LIMIT_TYPE" == "htb" ]; then
$TC class add dev $DEV parent 13:1 classid 13:$((113 + ${CLASS[0]})) htb rate ${CLASS[1]}kbit ceil ${CLASS[2]}kbit
else
$TC class add dev $DEV parent 13:1 classid 13:$((113 + ${CLASS[0]})) hfsc ls m2 ${CLASS[1]}kbit ul m2 ${CLASS[2]}kbit
fi
# Nasadíme sfq na dané třídy
$TC qdisc add dev $DEV parent 13:$((113 + ${CLASS[0]})) handle $((113 + ${CLASS[0]})):0 $SFQ
# Garantované třídy nepotřebují speciální třídu, protože se markují jen pomocí tc rovnou do dané třídy
#$TC filter add dev $DEV parent 1:0 protocol ip handle $((5 + ${CLASS[0]})) fw flowid 13:$((113 + ${CLASS[0]}))
#$TC filter add dev $DEV parent 13:0 protocol ip handle $((5 + ${CLASS[0]})) fw flowid 13:$((113 + ${CLASS[0]}))
done
IFS=$' \t\n'
done
((I++))
done
# Protože markování na každém zařízení zvlášť by bylo velmi mnoho pravidel pro iptables,
# tak použijeme markování na všech zařízeních, i tak zavedení pravidel trvá cca 6 vteřin.
if [ "$QOS_TYPE" == "layer7" ] || [ "$QOS_TYPE" == "layer7_esfq" ]; then
# Markování musíme provádět již v preroutingu, jinak nejsme schopni označit všechny pakety.
# ICMP - vzdy
$IPTABLES -t mangle -I PREROUTING -p icmp -j MARK --set-mark 1
# OSPF - vzdy
$IPTABLES -t mangle -I PREROUTING -p ospf -j MARK --set-mark 1
# UDP - vzdy
$IPTABLES -t mangle -I PREROUTING -p UDP -j MARK --set-mark 2
# HTML - jiny nekorektni zpusob markovani http, ale mnohem mene narocny
#$IPTABLES -t mangle -I PREROUTING -p TCP --dport 80 -j MARK --set-mark 3
# Označení paketů pomocí layer7 filtru, detekce některých protokolů zvyšuje odezvy
# 8.3.2009 - vyřazeny protokoly, které po cca 30 dnech měly nulové čítače
qos_mark_layer7 1 "bgp dhcp dns irc jabber snmp whois"
qos_mark_layer7 2 "quake-halflife worldofwarcraft"
# Do třídy 3 jdou všechna nezařazená data, takže jí není třeba označovat
qos_mark_layer7 3 ""
qos_mark_layer7 4 "ftp cvs biff h323 imap live365 pop3 rtsp shoutcast smtp ssl tftp"
qos_mark_layer7 5 "bittorrent directconnect edonkey http-itunes soulseek"
fi
echo "done."
# Označíme jednotlivé počítače v třídách
qos_guaranted_classes
}
qos_stop() {
echo -n "Stopping QoS..."
local I=""
local DEV=""
# Smažeme všechna pravidla v iptables
for I in `$IPTABLES -t mangle -L POSTROUTING -n -v --line-numbers | grep "set 0x" | awk '{print $1}' | sort -r -n`; do
$IPTABLES -t mangle -D POSTROUTING $I
done
for I in `$IPTABLES -t mangle -L PREROUTING -n -v --line-numbers | grep "set 0x" | awk '{print $1}' | sort -r -n`; do
$IPTABLES -t mangle -D PREROUTING $I
done
for I in `$IPTABLES -t mangle -L POSTROUTING -n -v --line-numbers | grep "todev" | awk '{print $1}' | sort -r -n`; do
$IPTABLES -t mangle -D POSTROUTING $I
done
for I in `$IPTABLES -t mangle -L PREROUTING -n -v --line-numbers | grep "todev" | awk '{print $1}' | sort -r -n`; do
$IPTABLES -t mangle -D PREROUTING $I
done
# Smažeme všechny root qdisky
while true; do
DEV="`$TC qdisc | grep -v 0: | awk '{print \$5}' | sort -u | sed -n 1p`"
[ "$DEV" == "" ] && break
$TC qdisc del dev "$DEV" root &>/dev/null
$TC qdisc del dev "$DEV" ingress &>/dev/null
done
# Deaktivujeme všechna ifb zařízení
while true; do
DEV="`$IP link show | grep ifb | grep UP | awk '{print \$2}' | sort -u | sed -n 1p`"
[ "$DEV" == "" ] && break
DEV="${DEV//:/}"
$IP link set "$DEV" down
done
# Odstraníme ifb modul z paměti
#rmmod -f ifb &>/dev/null
# Deaktivujeme všechna imq zařízení
while true; do
DEV="`$IP link show | grep imq | grep UP | awk '{print \$2}' | sort -u | sed -n 1p`"
[ "$DEV" == "" ] && break
DEV="${DEV//:/}"
$IP link set "$DEV" down
done
# Odstraníme imq modul z paměti
#rmmod -f imq &>/dev/null
echo "done."
}
qos_stats() {
$TC -s qdisc
}
# speciální garantované třídy
qos_guaranted_classes() {
[ "${#CLASS_1[*]}" -lt "1" ] && return 0
echo "Starting QoS guaranted classes..."
# lokální proměnné
local I=""
local J=""
local CLASS_DEV=""
local CLASS_MIN=""
local CLASS_MAX=""
local CLASS_USERS=""
local CLASSES=""
local RATE_MIN="0"
local USER=""
J="1"
while true; do
CLASS_DEV=CLASS_${J}_DEV
CLASS_DEV=${!CLASS_DEV}
[ "$CLASS_DEV" == "" ] && break
CLASS_MIN=CLASS_${J}_MIN
CLASS_MIN=${!CLASS_MIN}
CLASS_MAX=CLASS_${J}_MAX
CLASS_MAX=${!CLASS_MAX}
# klasické přiřazení nelze použít na pole
CLASS_USERS="CLASS_${J}[@]"
CLASS_USERS=( "${!CLASS_USERS}" )
# Přeskočíme prázdné třídy
if [ "${#CLASS_USERS[*]}" -lt "1" ]; then
((J++))
continue
fi
# Pokud není zadána maximální rychlost třídy
[ "$CLASS_MAX" == "" ] && CLASS_MAX="interface maximum"
echo "QoS class $J (dev: $CLASS_DEV, min: $CLASS_MIN kbit/s, max: $CLASS_MAX kbit/s):"
IFS=$'\t\n'
for USER in ${CLASS_USERS[@]}; do
IFS=$' \t\n'
USER=( $USER )
I="2"
while [ "${USER[$I]}" != "" ]; do
if [ "${USER[$I]:2:1}" == ":" ]; then
echo -e " user ${USER[1]}\twith mac ${USER[$I]}\ton ${USER[0]}\tlimited!"
else
echo -e " user ${USER[1]}\twith ip ${USER[$I]}\t\ton ${USER[0]}\tlimited!"
fi
qos_guaranted_class_add_user "$J" "${USER[$I]}" "${USER[0]}"
((I++))
done
done
IFS=$' \t\n'
((J++))
done
echo "done."
}
# formát: "třída" "ip, nebo mac" "rozhraní - nepovinné"
qos_guaranted_class_add_user() {
( [ "$1" == "" ] || [ "$2" == "" ] ) && return 0
# rozhraní na kterých je aktivní qos, vždy používáme alespoň sfq
local TC_DEVS=`$TC qdisc | grep sfq | awk '{print $5}' | sort -u`
# další lokální proměnné
local I=""
local DEV=""
local TC_DEV=""
local TC_DEVS_POM=""
local IMQ_DEV=""
local IFB_DEV=""
local DATA=""
local LINE=""
local IP="$2"
local MAC="`echo $2 | tr [:upper:] [:lower:]`"
local TC_NUM=""
local CLASS=""
# pokud ip, nebo mac už je zadaná, tak jí smažeme na všech rozhraních
qos_guaranted_class_del_user "$2"
# zjistíme jestli jde o MAC, nebo IP adresu
IFS=$'./\t\n'
IP=( $IP )
IFS=$':\t\n'
MAC=( $MAC )
IFS=$' \t\n'
# Je-li zadané rozhraní, tak musíme najít přidružené IMQ, nebo IFB
if [ "$3" != "" ] && [ "$3" != "all" ]; then
# IMQ z PREROUTINGu, musíme použít awk, protože iptables posílá * a ta se nedá převést do pole!
DATA=`$IPTABLES -t mangle -L PREROUTING -n -v | grep todev | awk '{print $6" "$12}'`
IFS=$'\t\n'
for LINE in $DATA; do
IFS=$' \t\n'
LINE=( ${LINE} )
if [ "${LINE[0]}" == "$3" ] && [ "${LINE[1]}" != "" ]; then
IMQ_DEV="imq${LINE[1]}"
break
fi
done
IFS=$' \t\n'
# ifb získáme z tc
IFB_DEV="`$TC filter list dev $3 parent ffff: | grep ifb | awk '{print \$9}'`"
IFB_DEV="${IFB_DEV//)/}"
for I in $TC_DEVS; do
[ "$3" == "$I" ] && TC_DEVS_POM=$TC_DEVS_POM" $I"
[ "$IFB_DEV" != "" ] && [ "$IFB_DEV" == "$I" ] && TC_DEVS_POM=$TC_DEVS_POM" $IFB_DEV"
[ "$IMQ_DEV" != "" ] && [ "$IMQ_DEV" == "$I" ] && TC_DEVS_POM=$TC_DEVS_POM" $IMQ_DEV"
done
[ "$TC_DEVS_POM" == "" ] && return 0
# Musíme odstranit první prázdný znak
TC_DEVS="${TC_DEVS_POM:1}"
fi
# samotné zařazení do třídy
for DEV in $TC_DEVS; do
# smažeme nejprve třídy 1:0 a pak 13:0
for CLASS in "1:0" "13:0"; do
# musíme najít další číslo kam budeme přidávat záznam
TC_NUM=$((`$TC filter list dev $DEV parent $CLASS | awk '{print $5}' | grep -v "4915" | sort -ug | tail -n 1` + 1))
if [ "${IP[3]}" != "" ]; then
$TC filter add dev $DEV parent $CLASS protocol ip prio $TC_NUM u32 match ip src $2 flowid 13:$((113 + $1))
$TC filter add dev $DEV parent $CLASS protocol ip prio $TC_NUM u32 match ip dst $2 flowid 13:$((113 + $1))
elif [ "${MAC[5]}" != "" ]; then
$TC filter add dev $DEV parent $CLASS protocol ip prio $TC_NUM u32 match u16 0x0800 0xffff at -2 match u32 0x${MAC[2]}${MAC[3]}${MAC[4]}${MAC[5]} 0xffffffff at -12 match u16 0x${MAC[0]}${MAC[1]} 0xffff at -14 flowid 13:$((113 + $1))
$TC filter add dev $DEV parent $CLASS protocol ip prio $TC_NUM u32 match u16 0x0800 0xffff at -2 match u16 0x${MAC[4]}${MAC[5]} 0xffff at -4 match u32 0x${MAC[0]}${MAC[1]}${MAC[2]}${MAC[3]} 0xffffffff at -8 flowid 13:$((113 + $1))
else
# nejedná se ani o ip ani o mac adresu
return 0
fi
done
done
return 0
}
# Pro mazání není třeba znát třídu ze které mažeme, protože by jedna ip, nebo mac
# neměla být ve více třídách.
#
# formát: "ip, nebo mac"
qos_guaranted_class_del_user() {
[ "$1" == "" ] && return 0
# Mažeme na všech rozhraních, kde je QoS
local TC_DEVS=`$TC qdisc | grep sfq | awk '{print $5}' | sort -u`
# lokální proměnné
local I=""
local DEV=""
local DATA=""
local LINE=""
local LINE_1=""
local LINE_2=""
local IP="$1"
local MAC="`echo $1 | tr [:upper:] [:lower:]`"
local IP_HEX=""
local MAC_1=""
local MAC_2=""
local MAC_3=""
local CLASS=""
local PRIO=""
local PRIO_PREV=""
# zjistíme jestli jde o MAC, nebo IP adresu, pro mac musíme převést velká písmena na malá
IFS=$'./\t\n'
IP=( $IP )
IFS=$':\t\n'
MAC=( $MAC )
IFS=$' \t\n'
if [ "${IP[3]}" != "" ]; then
# převedeme ip do formátu, který používá tc
IP_HEX=`printf '%02x%02x%02x%02x\n' ${IP[0]} ${IP[1]} ${IP[2]} ${IP[3]}`
elif [ "${MAC[5]}" != "" ]; then
MAC_1="00000800"
MAC_2="${MAC[2]}${MAC[3]}${MAC[4]}${MAC[5]}"
MAC_3="0000${MAC[0]}${MAC[1]}"
else
# Nejedná se ani o ip ani o mac adresu
return 0
fi
# zkontrolujeme všechna rozhraní
for DEV in $TC_DEVS; do
# smažeme nejprve třídy 1:0 a pak 13:0
for CLASS in "1:0" "13:0"; do
# načteme data z tc, kde jsou uloženy všechny zadané mac i ip adresy
IFS=$'\t\n'
DATA=( `$TC filter list dev $DEV parent $CLASS` )
IFS=$' \t\n'
I="0"
PRIO=""
PRIO_PREV=""
IFS=$'\t\n'
for LINE in ${DATA[@]}; do
# pro matchování nás nezajímá maska, proto masku oddělíme, platí jen v případě ip
IFS=$' /\t\n'
LINE=( $LINE )
IFS=$' \t\n'
# inkrementovat musíme ještě před continue
((I++))
if [ "${LINE[3]}" == "pref" ]; then
PRIO=${LINE[4]}
continue
fi
# dále nás zajímá jen match
[ "${LINE[0]}" != "match" ] && continue
# pokud neznáme prioritu, tak pokračujeme
[ "$PRIO" == "" ] && continue
# pokud jsme již jednou tuto prioritu mazali, tak pokračujeme
[ "$PRIO" == "$PRIO_PREV" ] && continue
# rozdělení podle ip, nebo mac
if [ "${IP[3]}" != "" ]; then
# pokud ip neodpovídá, tak pokračujeme
[ "${LINE[1]}" != "$IP_HEX" ] && continue
elif [ "${MAC[5]}" != "" ]; then
# jednotný match pro všechny mac adresy
[ "${LINE[1]}/${LINE[2]}" != "$MAC_1/0000ffff" ] && continue
# následující řádek musí obsahovat druhou část mac adresy, už nepoužíváme jako delimiter /
LINE_1=( ${DATA[$I]} )
[ "${LINE_1[1]}" != "$MAC_2/ffffffff" ] && continue
# další řádek musí obsahovat poslední část mac adresy
LINE_2=( ${DATA[$(($I + 1))]} )
[ "${LINE_2[1]}" != "$MAC_3/0000ffff" ] && continue
fi
# Daná ip už je matchovaná, proto pravidla smažeme
$TC filter del dev $DEV parent $CLASS protocol ip prio $PRIO 2>/dev/null
PRIO_PREV="$PRIO"
done
IFS=$' \t\n'
done
done
return 0
}
qos_mark_layer7() {
( [ "$1" == "" ] || [ "$2" == "" ] ) && return 0
# Lokální proměnné
local I=""
local O_DEV=""
local I_DEV=""
[ "$3" != "" ] && O_DEV="-o $3"
[ "$4" != "" ] && I_DEV="-i $4"
for I in $2; do
$IPTABLES -t mangle -I PREROUTING $O_DEV $I_DEV -m layer7 --l7proto $I -j MARK --set-mark $1
done
return 0
}