#!/bin/sh
#
# CZFree.Net RFC-QoS script
#
# date: 	4/5/2003
# authors:	Rakerihoo, Fyzik, Libor, Dzus
# references:	http://www.lartc.org/
#		http://luxik.cdi.cz/~devik/qos/htb/
#		http://10.24.2.1/forum/showthread.php?s=&threadid=9
# version:	2.1.3
#
# Changelog
#
# 04/01/04 [dzus]  podpora pro Jedi Knight, oprava prio u filtru, oprava filtru na FTP, zruseni PPTP class
# 20/11/03 [dzus]  zrusena H323 class, pridan filtr na TCP ACK, nastaveni quantum podle MTU
# 28/09/03 [dzus]  oprava bugu ve filtrech (bez prio to nechodi dobre)
# 27/09/03 [dzus]  konfigurace interfacu se nacita z ext souboru, pridan TOS minimize delay filtr
# 20/09/03 [dzus]  vyhazeni marku z IPtables, nyni pouze filtry v tc
# 01/09/03 [dzus]  vynechani internetoveho rozhrani z konfigurace
# 07/08/03 [fyzik] preference Inetoveho traffiku
# 31/07/03 [fyzik] podpora pro HL@tchor, airfree, fixes
# 05/05/03 [fyzik] podpora pro IRC, PPTP, H323, LDAP, DC, NTP
# 04/05/03 [fyzik] napsal uvod
# 01/05/03 [fyzik] non-CZF-RFC, inspirovan Liborovym Heaven QoS 
# 00/03/03 [Rakerihoo] napsal RFC-QoS :)
# 
# ToDo
# * zkusit a otestovat podtridy CZF-transfer, CZF-klient, CZF-shared a markovanat podle MAC 
# * pridat podporu ostatnich interaktivnich games


### Configuration START

IFACECONFFILE='/etc/network/iface_conf'
IPADDRFILE="/etc/network/ip_adresy"

NONCZFSPD='32'
AIRFREESPD='96'
XFERDIV='2'
DFLTDIV='2'

### Configuration STOP

if [ ! -f $IFACECONFFILE ]
then
    echo "Interface configuration file doesn't exist - program terminated" 1>&2
    exit 1
fi

IFACECONF=`grep -v '^[[:space:]]*#' $IFACECONFFILE | tr -d '\n' | sed -e 's/[[:space:]]*}[[:space:]]*/}\\\n/g'`
FACES=`echo -e $IFACECONF | sed -e 's/^[[:space:]]*interface[[:space:]]\+\([[:alnum:]]\+\).*/\1/'`

echo "Applying CZF-QOS rules"

echo "-Set global variables"
IPTABLES="`which iptables`"
TC="`which tc`"
IP="`which ip`"
IPT_RESTORE="`which iptables-restore`"

STOCHASIS="sfq perturb 10"

QUANTUMOFFS="500"

#$IPT_RESTORE < /etc/network/iptables

echo "-Remove Qdisc root classes"
for FACE in ${FACES} ; do
	$TC qdisc del dev ${FACE} root &>/dev/null
done

## qoseni podle IP - priklad
if [ -f $IPADDRFILE ]
then
    NONCZF=`grep -v '^[[:space:]]*#' $IPADDRFILE | grep NONCZF |  awk '{print $1;}'|tr , ' '`
    AIRFREE=`grep -v '^[[:space:]]*#' $IPADDRFILE | grep AIRFREE |  awk '{print $1;}' |tr , ' '`
fi

#echo "-Remove IPTables packet mangling, set defaults"

#$IPTABLES -t mangle -X
#$IPTABLES -t mangle -F INPUT
#$IPTABLES -t mangle -F OUTPUT
#$IPTABLES -t mangle -F PREROUTING
#$IPTABLES -t mangle -F POSTROUTING
#$IPTABLES -t mangle -F FORWARD

#$IPTABLES -t mangle -P INPUT ACCEPT
#$IPTABLES -t mangle -P OUTPUT ACCEPT
#$IPTABLES -t mangle -P PREROUTING ACCEPT
#$IPTABLES -t mangle -P POSTROUTING ACCEPT
#$IPTABLES -t mangle -P FORWARD ACCEPT


set_qos_classes () {
        echo "-Initializing QoS_base rules on interface $FACE (speed $SPEED)"

	$TC qdisc add dev ${FACE} root handle 1: htb default 300 r2q 2
        $TC class add dev ${FACE} parent 1:  classid 1:1   htb rate $((${SPEED}/2))kbit ceil ${SPEED}kbit burst 15k quantum ${QUANTUM}
	$TC class add dev ${FACE} parent 1:1 classid 1:5   htb rate 64kbit ceil 256kbit burst 5k prio 0				# SSH class
        $TC class add dev ${FACE} parent 1:1 classid 1:10  htb rate 64kbit ceil $((${SPEED}/4))kbit burst 5k prio 1		# interactive class
	$TC class add dev ${FACE} parent 1:1 classid 1:20  htb rate 32kbit ceil 64kbit burst 5k prio 2				# ping class
        $TC class add dev ${FACE} parent 1:1 classid 1:30  htb rate 32kbit ceil 64kbit burst 5k prio 0				# routing class
	$TC class add dev ${FACE} parent 1:1 classid 1:40  htb rate 32kbit ceil $((${SPEED}/${XFERDIV}))kbit burst 5k prio 3	# data transfer class
        $TC class add dev ${FACE} parent 1:1 classid 1:50  htb rate 32kbit ceil $((${SPEED}/${XFERDIV}))kbit burst 9k prio 4	# email class
	$TC class add dev ${FACE} parent 1:1 classid 1:60  htb rate 32kbit ceil $((${SPEED}/${XFERDIV}))kbit burst 8k prio 3	# squid class
	$TC class add dev ${FACE} parent 1:1 classid 1:300 htb rate 32kbit ceil $((${SPEED}/${DFLTDIV}))kbit burst 1k prio 4	# default trafic class
        $TC class add dev ${FACE} parent 1:1 classid 1:666 htb rate 32kbit ceil ${NONCZFSPD}kbit burst 1k prio 5	       	# unsupported trafic class
	$TC class add dev ${FACE} parent 1:1 classid 1:667 htb rate 32kbit ceil ${AIRFREESPD}kbit burst 1k prio 4		# local wireless free band
#	$TC class add dev ${FACE} parent 1:1 classid 1:999 htb rate 32kbit ceil $((${SPEED}/2))kbit burst 8k prio 4		# Inet traffic class

	$TC qdisc add dev ${FACE} parent 1:5 handle 5: $STOCHASIS	# SSH sub-classes
	$TC qdisc add dev ${FACE} parent 1:10 handle 10: $STOCHASIS	# interactive sub-classes
	$TC qdisc add dev ${FACE} parent 1:20 handle 20: $STOCHASIS	# ping sub-classes
	$TC qdisc add dev ${FACE} parent 1:30 handle 30: $STOCHASIS	# routing sub-classes
	$TC qdisc add dev ${FACE} parent 1:40 handle 40: $STOCHASIS	# data transfer sub-classes
	$TC qdisc add dev ${FACE} parent 1:50 handle 50: $STOCHASIS	# email sub-classes
	$TC qdisc add dev ${FACE} parent 1:60 handle 60: $STOCHASIS	# squid sub-classes
	$TC qdisc add dev ${FACE} parent 1:300 handle 300: $STOCHASIS	# default class
	$TC qdisc add dev ${FACE} parent 1:666 handle 666: $STOCHASIS	# unsupported 32kbit
	$TC qdisc add dev ${FACE} parent 1:667 handle 667: $STOCHASIS	# local wireless 32kbit
#	$TC qdisc add dev ${FACE} parent 1:999 handle 999: $STOCHASIS	# Inet traffic


	## SSH class
	# SSH
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 22 0xffff match ip protocol 0x6 0xff flowid 1:5
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 22 0xffff match ip protocol 0x6 0xff flowid 1:5

	## Interactive class
	# DNS
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 53 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 53 0xffff match ip protocol 0x6 0xff flowid 1:10
	# IRC
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 194 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 194 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 6667 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 6667 0xffff match ip protocol 0x6 0xff flowid 1:10
	# LDAP, LDAPs
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 389 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 389 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 636 0xffff match ip protocol 0x6 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 636 0xffff match ip protocol 0x6 0xff flowid 1:10
	# GAMES
	# Half-life
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 27015 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 27015 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 27016 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 27016 0xfffe match ip protocol 0x11 0xff flowid 1:10
	# UT2003
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 7777 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 7777 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 7778 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 7778 0xffff match ip protocol 0x11 0xff flowid 1:10
	# JEDI KNIGHT
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 28060 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 28060 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 28062 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 28062 0xffff match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 28070 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 28070 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 28072 0xfff8 match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 28072 0xfff8 match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 28080 0xfffe match ip protocol 0x11 0xff flowid 1:10
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 28080 0xfffe match ip protocol 0x11 0xff flowid 1:10
	
	# TOS mimimize delay
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip tos 0x10 0xff flowid 1:10
	# TCP ACK packets smaller than 64 bytes
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 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 1:10

	## Ping class
	# ICMP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip protocol 0x01 0xff flowid 1:20

	## Routing class
	# BGP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 179 0xffff match ip protocol 0x6 0xff flowid 1:30
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 179 0xffff match ip protocol 0x6 0xff flowid 1:30
	# OSPF
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip protocol 0x59 0xff flowid 1:30

	## Data transfer class
	# FTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 20 0xfffe match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 20 0xfffe match ip protocol 0x6 0xff flowid 1:40
	# HTTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 80 0xffff match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 80 0xffff match ip protocol 0x6 0xff flowid 1:40
	# HTTPS
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 443 0xffff match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 443 0xffff match ip protocol 0x6 0xff flowid 1:40
	# WebCache
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 8080 0xffff match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 8080 0xffff match ip protocol 0x6 0xff flowid 1:40
	# PPTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 1723 0xffff match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 1723 0xffff match ip protocol 0x6 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 1723 0xffff match ip protocol 0x11 0xff flowid 1:40
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 1723 0xffff match ip protocol 0x11 0xff flowid 1:40

	## E-mail, NTP, CVS class
	# POP3
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 110 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 110 0xffff match ip protocol 0x6 0xff flowid 1:50
	# IMAP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 143 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 143 0xffff match ip protocol 0x6 0xff flowid 1:50
	# SMTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 25 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 25 0xffff match ip protocol 0x6 0xff flowid 1:50
	# POP3S
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 995 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 995 0xffff match ip protocol 0x6 0xff flowid 1:50
	# IMAPS
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 993 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 993 0xffff match ip protocol 0x6 0xff flowid 1:50
	# SSMTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 465 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 465 0xffff match ip protocol 0x6 0xff flowid 1:50
	# NTP
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 123 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 123 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 123 0xffff match ip protocol 0x11 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 123 0xffff match ip protocol 0x11 0xff flowid 1:50
	# rsync 
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 673 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 673 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 673 0xffff match ip protocol 0x11 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 673 0xffff match ip protocol 0x11 0xff flowid 1:50
        # CVS
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 873 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 873 0xffff match ip protocol 0x6 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 873 0xffff match ip protocol 0x11 0xff flowid 1:50
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 873 0xffff match ip protocol 0x11 0xff flowid 1:50

	## Squid class
	# HTTP port
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 3128 0xffff match ip protocol 0x6 0xff flowid 1:60
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 3128 0xffff match ip protocol 0x6 0xff flowid 1:60
	# ICP port
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 3130 0xffff match ip protocol 0x6 0xff flowid 1:60
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 3130 0xffff match ip protocol 0x6 0xff flowid 1:60

	## Unsupported class
	# Kazaa
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip sport 1214 0xffff match ip protocol 0x6 0xff flowid 1:666
	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 2 u32 match ip dport 1214 0xffff match ip protocol 0x6 0xff flowid 1:666

	# IP range of DHCP for airfree AP on this router
	for ipaddr in $AIRFREE
	do 
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip src $ipaddr flowid 1:667
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip dst $ipaddr flowid 1:667
	done
	# non-CZF-RFC - violators of RFCs
       	for ipaddr in $NONCZF
	do
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip src $ipaddr flowid 1:666
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip dst $ipaddr flowid 1:666
	done

	## Internet class
	# IPtables rule
#	$IPTABLES -t mangle -A FORWARD -s ! 10.0.0.0/8 -o ${FACE} -j MARK  --set-mark 999
#	$IPTABLES -t mangle -A FORWARD -d ! 10.0.0.0/8 -o ${FACE} -j MARK  --set-mark 999
	# IPtables mark filter
#	$TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 handle 999 fw flowid 1:999
}

for FACE in $FACES
do
    TYPE=`echo -e $IFACECONF | grep $FACE | sed -e "s/^.*{.*type[[:space:]]\+\([[:alpha:]]\+\).*}.*/\1/"`
    if [ "$TYPE" != 'transit' ]
    then
	continue
    fi
    SPEED=`echo -e $IFACECONF | grep $FACE | sed -e "s/^.*{.*speed[[:space:]]\+\([[:digit:]]\+\).*}.*/\1/;t;d"`
    QUANTUM=`echo -e $IFACECONF | grep $FACE | sed -e "s/^.*{.*quantum[[:space:]]\+\([[:digit:]]\+\).*}.*/\1/;t;d"`

    if [ -z "$QUANTUM" ]
    then
	MTU=`$IP l | grep $FACE | sed -e "s/^.*mtu[[:space:]]\+\([[:digit:]]\+\).*/\1/"`
	QUANTUM=$(($QUANTUMOFFS+$MTU))
    fi
    set_qos_classes
done

exit 0
