#!/bin/sh
#
# Habrova iGW-QoS script
# Created by Dzus
# Contributed: Fyzik, Jaha2x, Rakerihoo
#
# Version: 1.3.4
# Released under GNU/GPL License 
#
# Changelog:
# 29.12.2003 [fyzik] komentare, release pod GPL
# 18.11.2003 [dzus]  pridana class pro CZF traffic
# 11.11.2003 [fyzik] jedeme na 1M pres THDN (eth1), zatim nejsme qoseni
# 10.11.2003 [fyzik] Kazza->DROP
# 27.10.2003 [dzus]  odmaznuti pesimistickych komentaru :)
# 27.10.2003 [fyzik] zpet prepnuto na 512
# 21.09.2003 [fyzik] pokusne 64->80
# 20.09.2003 [fyzik] 64kbps tridy a,b,c
# 09.09.2003 [Dzus]  pridan shaping uploadu
# 08.09.2003 [Dzus]  pridana podpora pro 64kbit class
#

echo "Applying iGW-QOS rules"
                                                                                                             
echo "-Set global variables"
IPTABLES="`which iptables`"
TC="`which tc`"
IP="`which ip`"
CLASSINFOFILE="classinfo"

### Configuration START
# vsechna cisla jsou v kbit/sec

# Link speed configuration
# max rychlost linky by mela byt nastavena asi o 10% niz nez je skutecna max. rychlost

# Predpokladana situace je, ze Vas ISP umozuje CZF peering pres interface, kterym jste k nemu pripojenim jako to dela Thundernet.
# LINK_SPD je rychlost media, INET_SPD je zakoupena konetivita do Inetu.

LINK_SPD="1500"
INET_SPD="980"

SH128_SPD="128"
SH64_SPD="64"

UNSUPPORT_SPD="32"
UNSUPPORT_MAX="32"

AIRFREE_SPD="32"
AIRFREE_MAX="64"

DEFAULT_SPD="32"
DEFAULT_MAX="64"


# Inet interface
INETIFACE="eth1"

### Configuration STOP

set_qos_classes () {
    echo "-Remove Qdisc root classes, clear tables (${FACE})"
    $TC qdisc del dev ${FACE} root &>/dev/null
    
    echo "-Create HTB root qdisc (${FACE})"
    $TC qdisc add dev ${FACE} root handle 1: htb default 99
    echo "-Create HTB Inet classes (${FACE})"
    $TC class add dev ${FACE} parent 1:  classid 1:1   htb rate ${LINK_SPD}kbit ceil ${LINK_SPD}kbit burst 20k			# whole line
    $TC class add dev ${FACE} parent 1:1 classid 1:2   htb rate ${INET_SPD}kbit ceil ${INET_SPD}kbit burst 20k			prio 1  # Inet class
    $TC class add dev ${FACE} parent 1:1 classid 1:3   htb rate ${OTHER_SPD}kbit ceil ${LINK_SPD}kbit burst 20k			prio 2  # CZF class
    $TC class add dev ${FACE} parent 1:2 classid 1:10  htb rate ${SHARED_SPD}kbit ceil ${INET_SPD}kbit burst 16k		prio 1	# shared link root class (OKFOLX)
    $TC class add dev ${FACE} parent 1:2 classid 1:20  htb rate ${SH128_SPD}kbit ceil ${SH128_SPD}kbit burst 10k		prio 1	# 128kbit (SH128)
    $TC class add dev ${FACE} parent 1:2 classid 1:30  htb rate ${SH64_SPD}kbit ceil ${SH64_SPD}kbit burst 10k			prio 1	# 64kbit (SH64) local
    $TC class add dev ${FACE} parent 1:2 classid 1:40  htb rate ${SH64_SPD}kbit ceil ${SH64_SPD}kbit burst 10k			prio 1	# 64kbit (SH64) wifi 1
    $TC class add dev ${FACE} parent 1:2 classid 1:50  htb rate ${SH64_SPD}kbit ceil ${SH64_SPD}kbit burst 10k			prio 1	# 64kbit (SH64) wifi 2
    $TC class add dev ${FACE} parent 1:2 classid 1:80  htb rate ${AIRFREE_SPD}kbit ceil ${AIRFREE_MAX}kbit burst 2k		prio 2	# local wireless free band (AIRFREE)
    $TC class add dev ${FACE} parent 1:2 classid 1:99  htb rate ${DEFAULT_SPD}kbit ceil ${DEFAULT_MAX}kbit burst 2k	    	prio 3	# default trafic class
    $TC class add dev ${FACE} parent 1:2 classid 1:100 htb rate ${UNSUPPORT_SPD}kbit ceil ${UNSUPPORT_MAX}kbit burst 2k 	prio 4	# unsupported trafic class

    echo "-Add stochasic fairness to Inet subclasses (${FACE})"
    $TC qdisc add dev ${FACE} parent 1:3   handle 3: $STOCHASIS   # CZF class
    $TC qdisc add dev ${FACE} parent 1:80  handle 80: $STOCHASIS  # local wireless
    $TC qdisc add dev ${FACE} parent 1:99  handle 99: $STOCHASIS  # default class
    $TC qdisc add dev ${FACE} parent 1:100 handle 100: $STOCHASIS # unsupported

    # Output class descriptions to the file
    echo "interface $FACE {" >> $CLASSINFOFILE
    echo "  1:1 'Root class'" >> $CLASSINFOFILE
    echo "  1:2 'Inet class'" >> $CLASSINFOFILE
    echo "  1:3 'CZF class'" >> $CLASSINFOFILE
    echo "  1:10 'Shared link class (OKFOLX)'" >> $CLASSINFOFILE
    echo "  1:20 '128kbit class (SH128)'" >> $CLASSINFOFILE
    echo "  1:30 '64kbit class (SH64a)'" >> $CLASSINFOFILE
    echo "  1:40 '64kbit class (SH64b)'" >> $CLASSINFOFILE
    echo "  1:50 '64kbit class (SH64c)'" >> $CLASSINFOFILE
    echo "  1:80 'Airfree class'" >> $CLASSINFOFILE
    echo "  1:99 'Default class'" >> $CLASSINFOFILE
    echo "  1:100 'Unsupported class'" >> $CLASSINFOFILE

    echo "-Create class filters (${FACE})"

    # CZF
    $TC filter add dev ${FACE} parent 1:0 protocol ip u32 match ip src 10.0.0.0/8 match ip dst 10.0.0.0/8 flowid 1:3

    # unsupported
    for ipgroup in $NONCZF
    do
	ipaddrs=`echo $ipgroup | tr "," " "`
        for ipaddr in $ipaddrs
	do
	    $TC filter add dev ${FACE} parent 1:0 protocol ip u32 match ip $SRCDST $ipaddr flowid 1:100
        done
    done

    for ipgroup in $NEPLATICI
    do 
	ipaddrs=`echo $ipgroup | tr "," " "`
        for ipaddr in $ipaddrs
	do
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:100
        done
    done

    # IP range of DHCP for airfree AP on this router
    for ipgroup in $AIRFREE
    do 
	ipaddrs=`echo $ipgroup | tr "," " "`
        for ipaddr in $ipaddrs
	do
    	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:30
	done
    done

    CLASS_ID=100;

    for ipgroup in $OKFOLX			# NGO shared data class
    do
	CLASS_ID=$(($CLASS_ID+1))
        echo "  1:$CLASS_ID '$ipgroup'" >> $CLASSINFOFILE
        $TC class add dev ${FACE} parent 1:10 classid 1:${CLASS_ID} htb rate ${SHARED_SUB_SPD}kbit ceil ${SHARED_MAX_SPD}kbit burst 5k
	$TC qdisc add dev ${FACE} parent 1:${CLASS_ID} handle ${CLASS_ID}: $STOCHASIS
        ipaddrs=`echo $ipgroup | tr "," " "`
        for ipaddr in $ipaddrs
	do
	    $TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:${CLASS_ID}
        done
    done

    if [ "$SH128_NUM" -gt 0 ]			# 128 kbps class
    then
	CLASS_ID=200;
        for ipgroup in $SH128
	do
    	    CLASS_ID=$(($CLASS_ID+1))
            echo "  1:$CLASS_ID '$ipgroup'" >> $CLASSINFOFILE
    	    $TC class add dev ${FACE} parent 1:20 classid 1:${CLASS_ID} htb rate ${SH128_SUB_SPD}kbit ceil ${SH128_SPD}kbit burst 5k
    	    $TC qdisc add dev ${FACE} parent 1:${CLASS_ID} handle ${CLASS_ID}: $STOCHASIS
	    ipaddrs=`echo $ipgroup | tr "," " "`
	    for ipaddr in $ipaddrs
	    do
		$TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:${CLASS_ID}
	    done
	done
    fi

    if [ "$SH64a_NUM" -gt 0 ]			# 64kbps class a
    then
	CLASS_ID=300;
	for ipgroup in $SH64a
	do
	    CLASS_ID=$(($CLASS_ID+1))
            echo "  1:$CLASS_ID '$ipgroup'" >> $CLASSINFOFILE
	    $TC class add dev ${FACE} parent 1:30 classid 1:${CLASS_ID} htb rate ${SH64a_SUB_SPD}kbit ceil ${SH64_SPD}kbit burst 5k
	    $TC qdisc add dev ${FACE} parent 1:${CLASS_ID} handle ${CLASS_ID}: $STOCHASIS
	    ipaddrs=`echo $ipgroup | tr "," " "`
	    for ipaddr in $ipaddrs
	    do
		$TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:${CLASS_ID}
	    done
	done
    fi
    
    if [ "$SH64b_NUM" -gt 0 ]			# 64kpbs class b
    then
	CLASS_ID=400;
	for ipgroup in $SH64b
	do
	    CLASS_ID=$(($CLASS_ID+1))
            echo "  1:$CLASS_ID '$ipgroup'" >> $CLASSINFOFILE
	    $TC class add dev ${FACE} parent 1:40 classid 1:${CLASS_ID} htb rate ${SH64b_SUB_SPD}kbit ceil ${SH64_SPD}kbit burst 5k
	    $TC qdisc add dev ${FACE} parent 1:${CLASS_ID} handle ${CLASS_ID}: $STOCHASIS
	    ipaddrs=`echo $ipgroup | tr "," " "`
	    for ipaddr in $ipaddrs
	    do
		$TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:${CLASS_ID}
	    done
	done
    fi
    
    if [ "$SH64c_NUM" -gt 0 ]			# 64kbps class c
    then
	CLASS_ID=500;
	for ipgroup in $SH64c
	do
	    CLASS_ID=$(($CLASS_ID+1))
            echo "  1:$CLASS_ID '$ipgroup'" >> $CLASSINFOFILE
	    $TC class add dev ${FACE} parent 1:50 classid 1:${CLASS_ID} htb rate ${SH64c_SUB_SPD}kbit ceil ${SH64_SPD}kbit burst 5k
	    $TC qdisc add dev ${FACE} parent 1:${CLASS_ID} handle ${CLASS_ID}: $STOCHASIS
	    ipaddrs=`echo $ipgroup | tr "," " "`
	    for ipaddr in $ipaddrs
	    do
		$TC filter add dev ${FACE} parent 1:0 protocol ip prio 1 u32 match ip $SRCDST $ipaddr flowid 1:${CLASS_ID}
	    done
	done
    fi
    
    echo "}" >> $CLASSINFOFILE
}


IMQDOWNNUM=0
IMQDOWN=imq$IMQDOWNNUM
IMQUPNUM=1
IMQUP=imq$IMQUPNUM

rm $CLASSINFOFILE > /dev/null 2>&1

$IP link set $IMQDOWN down
$IP link set $IMQUP down
$IP link set $IMQDOWN up
$IP link set $IMQUP up

$IPTABLES -t nat -D POSTROUTING -o eth1 -s 10.0.0.0/8 -d ! 10.0.0.0/8 -j MASQUERADE 2>/dev/null
$IPTABLES -t nat -A POSTROUTING -o eth1 -s 10.0.0.0/8 -d ! 10.0.0.0/8 -j MASQUERADE

$IPTABLES -F FORWARD
# Drop dangerous traffic - all P2P if possible
# kazza
$IPTABLES -A FORWARD -o $INETIFACE -p udp --dport 1214 -j DROP
$IPTABLES -A FORWARD -o $INETIFACE -p tcp --dport 1214 -j DROP
# mldonkey
$IPTABLES -A FORWARD -o $INETIFACE -p tcp --dport 4662 -j DROP
$IPTABLES -A FORWARD -o $INETIFACE -p udp --dport 4662 -j DROP


$IPTABLES -F -t mangle
$IPTABLES -t mangle -A FORWARD -i $INETIFACE -j IMQ --todev $IMQDOWNNUM
#$IPTABLES -t mangle -A PREROUTING -i $INETIFACE -j IMQ --todev $IMQDOWNNUM
$IPTABLES -t mangle -A OUTPUT  -o $INETIFACE -j IMQ --todev $IMQUPNUM
$IPTABLES -t mangle -A FORWARD -o $INETIFACE -j IMQ --todev $IMQUPNUM

echo "Configuring iGW interface ${INETIFACE} at speed $INET_SPD"
                                                                                                             
STOCHASIS="sfq perturb 10"

FACES="$IMQDOWN"
                                                                                                             
## qoseni podle IP 
IP_ADRESY="/etc/network/ip_adresy"
NONCZF=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' | grep NONCZF |  awk '{print $1;}'`
AIRFREE=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' | grep AIRFREE |  awk '{print $1;}'`
NEPLATICI=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep NEPLATIC | awk '{print $1;}'`
OKFOLX=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep  OKFOLX | awk '{print $1;}'`
SH128=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep  SH128 | awk '{print $1;}'`
SH64a=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep  SH64a | awk '{print $1;}'`
SH64b=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep  SH64b | awk '{print $1;}'`
SH64c=`cat $IP_ADRESY | grep -v '^[[:space:]]*#' |  grep  SH64c | awk '{print $1;}'`

## Speed calculations
SHARED_SPD=$(($INET_SPD-$SH128_SPD-$SH64_SPD-$AIRFREE_SPD-$UNSUPPORT_SPD-$DEFAULT_SPD))
SHARED_NUM=`echo $OKFOLX | awk '{print NF;}'`

SHARED_MAX_SPD=$(($INET_SPD-$SH128_SPD))
SHARED_SUB_SPD=$(($SHARED_SPD/$SHARED_NUM))

OTHER_SPD=$(($LINK_SPD-$INET_SPD))


SH128_NUM=`echo $SH128 | awk '{print NF;}'`
if [ "$SH128_NUM" -gt 0 ]
then
    SH128_SUB_SPD=$(($SH128_SPD/$SH128_NUM))
fi

SH64a_NUM=`echo $SH64a | awk '{print NF;}'`
if [ "$SH64a_NUM" -gt 0 ]
then
    SH64a_SUB_SPD=$(($SH64_SPD/$SH64a_NUM))
fi

SH64b_NUM=`echo $SH64b | awk '{print NF;}'`
if [ "$SH64b_NUM" -gt 0 ]
then
    SH64b_SUB_SPD=$(($SH64_SPD/$SH64b_NUM))
fi

SH64c_NUM=`echo $SH64c | awk '{print NF;}'`
if [ "$SH64c_NUM" -gt 0 ]
then
    SH64c_SUB_SPD=$(($SH64_SPD/$SH64c_NUM))
fi

SRCDST="dst"
FACE=$IMQDOWN
set_qos_classes

SRCDST="src"
FACE=$IMQUP
set_qos_classes
