#----------------------------------------------------------------------------
# /etc/rc.d/rc.qos - configuration of OPT_QOS Version 0.4s
#
# Creation:     02.05.2001  he
# Last Update:  08.12.2002  he
#
# Angepasst von Lutz Lisseck für QOS auf FLI-Dienste (IP 1.1.1.1 einsetzen)
# Last Update:	16.03.2004 	ll 
#----------------------------------------------------------------------------

if [ "$QOS_DO_DEBUG" = yes ]
then
    set -x
fi

/usr/local/bin/colecho "enabling Quality of Service ..." gn


TC=/sbin/tc
IC=/sbin/ipchains

DYNCHAIN=/var/run/dynchain.qos

/sbin/insmod sch_htb.o
/sbin/insmod sch_sfq.o
/sbin/insmod sch_prio.o
/sbin/insmod cls_u32.o
/sbin/insmod cls_fw.o


## --- global settings --- ##

burst="2k"
mtu="1500b"
perturb="10"


## --- initialize vars --- ##

idx_down=1
idx_up=1


## --- inbound traffic --- ##

if [ "$QOS_INTERNET_DEFAULT_DOWN" != "0" ]
then
  QOS_INTERNET_DEFAULT_DOWN=`/usr/bin/expr $QOS_INTERNET_DEFAULT_DOWN + 2`
else
  QOS_INTERNET_DEFAULT_DOWN="1"
fi

## HTB für Inbound-Device aktivieren:
$TC qdisc add dev $QOS_LOCALNET_DEV root handle 10: htb default $QOS_INTERNET_DEFAULT_DOWN r2q 2

## Klasse für die den beschränkten Internet Traffic (Traffic, nicht aus dem maskierte LAN kommt) einrichten.
$TC class add dev $QOS_LOCALNET_DEV parent 10: classid 10:1 htb rate $QOS_INTERNET_BAND_DOWN \
    burst $burst

## Klasse für den unbeschränkten LAN-Traffic einrichten.
$TC class add dev $QOS_LOCALNET_DEV parent 10: classid 10:2 htb rate $QOS_LOCALNET_BAND
$TC qdisc add dev $QOS_LOCALNET_DEV parent 10:2 sfq quantum $mtu perturb $perturb

## Filter einrichten, der Den gesamten Traffic, der aus dem maskierten LAN kommt auch in die LAN-Traffic Klasse steckt.
for j in $MASQ_NETWORK
do
  $TC filter add dev $QOS_LOCALNET_DEV parent 10: protocol ip prio $idx_down u32 match ip src $j flowid 10:2
  idx_down=`/usr/bin/expr $idx_down + 1`
done



## --- outbound traffic --- ##

QOS_INTERNET_DEFAULT_UP=`/usr/bin/expr $QOS_INTERNET_DEFAULT_UP + 1`

## HTB für Outbound-Device aktivieren:
$TC qdisc add dev $QOS_INTERNET_DEV root handle 20: htb default $QOS_INTERNET_DEFAULT_UP r2q 1

## Standardklasse einrichten:
$TC class add dev $QOS_INTERNET_DEV parent 20: classid 20:1 htb rate $QOS_INTERNET_BAND_UP burst $burst


## --- SYN-Flood Protection --- ##

#$IC -N qosin
#$IC -I input -i $QOS_LOCALNET_DEV -j qosin

#$TC qdisc add dev $QOS_INTERNET_DEV handle 30: ingress

#$IC -A qosin -i $QOS_LOCALNET_DEV -p tcp --syn -m 2000

#$TC filter add dev $QOS_INTERNET_DEV parent 30:0 protocol ip prio 100 handle 2000 fw \
#  police rate 2kbit burst 40 mtu 9k drop flowid :1

#$IC -A qosin -j RETURN


## --- Klassen einrichten --- ##

idx=1

while [ "$idx" -le "$QOS_CLASS_N" ]
do
  eval parent='$QOS_CLASS_'$idx'_PARENT'
  eval maxband='$QOS_CLASS_'$idx'_MAXBANDWIDTH'
  eval minband='$QOS_CLASS_'$idx'_MINBANDWIDTH'
  eval direction='$QOS_CLASS_'$idx'_DIRECTION'
  eval prio='$QOS_CLASS_'$idx'_PRIO'

  if [ "$prio" = "" ]
  then
    prio=""
  else
    prio='prio '$prio
  fi

  if [ "$maxband" != "" ]
  then
    maxband='ceil '$maxband
  else
    maxband=""
  fi

  if [ "$direction" = "down" ]
  then

    class=`/usr/bin/expr $idx + 2`
    eval class='10:'$class

    if [ "$parent" = "0" ]
    then
      parent="10:1"
    else
      parent=`/usr/bin/expr $parent + 2`
      eval parent='10:'$parent
    fi

    $TC class add dev $QOS_LOCALNET_DEV parent $parent classid $class htb \
      rate $minband $maxband burst $burst $prio
    $TC qdisc add dev $QOS_LOCALNET_DEV parent $class sfq quantum $mtu perturb $perturb
  fi

  if [ "$direction" = "up" ]
  then

    class=`/usr/bin/expr $idx + 1`
    eval class='20:'$class

    if [ "$parent" = "0" ]
    then
      parent="20:1"
    else
      parent=`/usr/bin/expr $parent + 1`
      eval parent='20:'$parent
    fi

    $TC class add dev $QOS_INTERNET_DEV parent $parent classid $class htb \
      rate $minband $maxband burst $burst $prio
    $TC qdisc add dev $QOS_INTERNET_DEV parent $class sfq quantum $mtu perturb $perturb
  fi
  idx=`/usr/bin/expr $idx + 1`
done


## --- Filterregeln einrichten --- ###

$IC -N qosout
# $IC -I input -i $QOS_LOCALNET_DEV -j qosout
$IC -I input -i ! $QOS_INTERNET_DEV -j qosout

idx=1

while [ "$idx" -le "$QOS_FILTER_N" ]
do
  eval class='$QOS_FILTER_'$idx'_CLASS'
  eval ip='$QOS_FILTER_'$idx'_IP'
  eval port='$QOS_FILTER_'$idx'_PORT'
  eval type='$QOS_FILTER_'$idx'_TYPE'
  eval option='$QOS_FILTER_'$idx'_OPTION'

  eval class_direction='$QOS_CLASS_'$class'_DIRECTION'

  u32_param=""

  if [ "$class_direction" = "down" ]
  then

    class=`/usr/bin/expr $class + 2`
    eval class='10:'$class
    parent="10:0"

    if [ "$ip" != "" ]
    then
      u32_param="match ip dst $ip "
    fi

    if [ "$port" != "" ]
    then
      if [ "$type" = "client" ]
      then
        u32_param="$u32_param match ip sport $port 0xffff "
      fi
      if [ "$type" = "server" ]
      then
        u32_param="$u32_param match ip dport $port 0xffff "
      fi
    fi

    if [ "$option" = "ACK" ]
    then
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip protocol 6 0xff \
        match u8 0x05 0x0f at 0 \
        match u16 0x0000 0xffc0 at 2 \
        match u8 0x10 0xff at 33 \
        flowid $class
      idx_down=`/usr/bin/expr $idx_down + 1`
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip protocol 6 0xff \
        match u8 0x10 0x10 at nexthdr+13 \
        match u16 0x0034 0xffff at 2 \
        flowid $class
      idx_down=`/usr/bin/expr $idx_down + 1`
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip protocol 6 0xff match \
        u8 0x10 0x10 at nexthdr+13 \
        match u16 0x0028 0xffff at 2 \
        flowid $class
    elif [ "$option" = "ICMP" ]
    then
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip protocol 1 0xff \
        flowid $class
    elif [ "$option" = "TOSMD" ]
    then
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip tos 0x10 0xff  \
        flowid $class
    elif [ "$option" = "TOSMT" ]
    then
      $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip tos 0x08 0xff \
        flowid $class
    elif [ "$option" = "TOSMR" ]
    then
      $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip tos 0x04 0xff \
        flowid $class
    elif [ "$option" = "TOSMC" ]
    then
      $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        match ip tos 0x02 0xff \
        flowid $class
    else
      $TC filter add dev $QOS_LOCALNET_DEV parent $parent protocol ip prio $idx_down u32 $u32_param \
        flowid $class
    fi
    idx_down=`/usr/bin/expr $idx_down + 1`
  fi

  if [ "$class_direction" = "up" ]
  then

    class=`/usr/bin/expr $class + 1`
    eval class='20:'$class
    parent="20:0"

    if [ "$ip" != "" ]
    then
		
		# Wenn die spezielle IP hier steht, IPCHAINS anders aufbauen
		if [ "$ip" = "1.1.1.1" ]
		then
		  u32_param="--src \$inetip "
	
		  if [ "$port" != "" ]
		  then
			if [ "$type" = "client" ]
			then
			  u32_param="$u32_param --dport $port "
			elif [ "$type" = "server" ]
			then
			  u32_param="$u32_param --sport $port "
			fi
		  fi
	
		  if [ "$option" = "ICMP" ]
		  then
		    echo "# Chain nur ICMP" >> $DYNCHAIN
			echo "\$IC -A qinetout -p icmp $u32_param -m $idx_up -j RETURN" >> $DYNCHAIN
			echo "" >> $DYNCHAIN
		  elif [ "$port" != "" ]
		  then
		    echo "# Chain mit Ports ($type)" >> $DYNCHAIN
			echo "\$IC -A qinetout -p tcp $u32_param -m $idx_up -j RETURN" >> $DYNCHAIN
			echo "\$IC -A qinetout -p udp $u32_param -m $idx_up -j RETURN" >> $DYNCHAIN
			echo "\$IC -A qinetout -p icmp $u32_param -m $idx_up -j RETURN" >> $DYNCHAIN
			echo "" >> $DYNCHAIN
		  else
		  	echo "# Chain nur mit IP" >> $DYNCHAIN
			echo "\$IC -A qinetout $u32_param -m $idx_up -j RETURN" >> $DYNCHAIN
			echo "" >> $DYNCHAIN
		  fi
	
		  $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up \
			handle $idx_up fw flowid $class
		
		else
		  u32_param="--src $ip "
	
		  if [ "$port" != "" ]
		  then
			if [ "$type" = "client" ]
			then
			  u32_param="$u32_param --dport $port "
			elif [ "$type" = "server" ]
			then
			  u32_param="$u32_param --sport $port "
			fi
		  fi
	
		  if [ "$option" = "ICMP" ]
		  then
			$IC -A qosout -p icmp $u32_param -m $idx_up -j RETURN
		  elif [ "$port" != "" ]
		  then
			$IC -A qosout -p tcp $u32_param -m $idx_up -j RETURN
			$IC -A qosout -p udp $u32_param -m $idx_up -j RETURN
			$IC -A qosout -p icmp $u32_param -m $idx_up -j RETURN
		  else
			$IC -A qosout $u32_param -m $idx_up -j RETURN
		  fi
	
		  $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up \
			handle $idx_up fw flowid $class
			
		fi
		
		
    else

      if [ "$port" != "" ]
      then
        if [ "$type" = "client" ]
        then
          u32_param="match ip dport $port 0xffff "
        elif [ "$type" = "server" ]
        then
          u32_param="match ip sport $port 0xffff "
        fi
      fi

      if [ "$option" = "ACK" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip protocol 6 0xff \
          match u8 0x05 0x0f at 0 \
          match u16 0x0000 0xffc0 at 2 \
          match u8 0x10 0xff at 33 \
          flowid $class
        idx_down=`/usr/bin/expr $idx_up + 1`
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip protocol 6 0xff \
          match u8 0x10 0x10 at nexthdr+13 \
          match u16 0x0034 0xffff at 2 \
          flowid $class
        idx_down=`/usr/bin/expr $idx_up + 1`
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip protocol 6 0xff match \
          u8 0x10 0x10 at nexthdr+13 \
          match u16 0x0028 0xffff at 2 \
          flowid $class
      elif [ "$option" = "ICMP" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip protocol 1 0xFF \
          flowid $class
      elif [ "$option" = "TOSMD" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip tos 0x10 0xff \
          flowid $class
      elif [ "$option" = "TOSMT" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip tos 0x08 0xff \
          flowid $class
      elif [ "$option" = "TOSMR" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip tos 0x04 0xff \
          flowid $class
      elif [ "$option" = "TOSMC" ]
      then
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          match ip tos 0x02 0xff \
          flowid $class
      else
        $TC filter add dev $QOS_INTERNET_DEV parent $parent protocol ip prio $idx_up u32 $u32_param \
          flowid $class
      fi
    fi
    idx_up=`/usr/bin/expr $idx_up + 1`
  fi

  idx=`/usr/bin/expr $idx + 1`
done

$IC -A qosout -j RETURN

## -- Dynamische IPCHAINS einrichten, falls nötig -- ##
if [ -f $DYNCHAIN ]
then
	/usr/local/bin/colecho "... activating dynamic QoS ..." br b br

	# Neue qinetout-Chain aufbauen
	$IC -N qinetout
	
	( 	echo "#!/bin/sh"
		echo "# ip-up.dynqos (automatisch erzeugt von rc.qos)"
		echo ""
		echo "# Wait for end of boot"
		echo "while [ ! -f /var/run/boot_finished ]"
		echo "do"
		echo "	echo \"Waiting for boot sequence to end...\""
		echo "	sleep 10"
		echo "done"
		echo ""
		echo "inetip=\$local"
		echo "IC=/sbin/ipchains"
		echo ""
		echo "# --- Alte qinetout-Chains löschen ---"
		echo "\$IC -D output -i $QOS_INTERNET_DEV -j qinetout"
		echo "\$IC -F qinetout"
		echo ""
		echo "# --- Dynamische Filterregeln einbauen ---"
	) > /etc/ppp/ip-up.dynqos	
	
	cat $DYNCHAIN >> /etc/ppp/ip-up.dynqos
	
	(	echo ""
		echo "# --- Internetverkehr durch die qinetout-Chain leiten ---"
		echo "\$IC -A qinetout -j RETURN"
		echo "\$IC -I output -i $QOS_INTERNET_DEV -j qinetout"
		echo ""
		echo "# That's it ;-)"
	) >> /etc/ppp/ip-up.dynqos
	
	( 	echo "#!/bin/sh"
		echo "# ip-down.dynqos (automatisch erzeugt von rc.qos)"
		echo ""
		echo "IC=/sbin/ipchains"
		echo ""
		echo "# --- Alte qinetout-Chains löschen ---"
		echo "\$IC -D output -i $QOS_INTERNET_DEV -j qinetout"
		echo "\$IC -F qinetout"
		echo ""
	) > /etc/ppp/ip-down.dynqos
	
	/bin/chmod +x /etc/ppp/ip-up.dynqos
	/bin/chmod +x /etc/ppp/ip-down.dynqos



fi



set +x

/usr/local/bin/colecho "... finished" gn
