#!/bin/sh PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH DEV=eth0 if [ $# != 2 ]; then exit 1; fi DOWNSTREAM=$[256 * $1 / 100] UPSTREAM=160 tcf () { if ! tc "$@" ; then echo Failed on: tc "$@" exit 1 fi } ut_min_kbit=60 ut_max_kbit=$UPSTREAM udp_min_kbit=40 udp_max_kbit=$[$UPSTREAM*80/100] ssh_min_kbit=50 ssh_max_kbit=150 ack_min_kbit=$[$UPSTREAM*20/100] ack_max_kbit=$[$UPSTREAM*30/100] rest_min_kbit=$[$UPSTREAM-$ut_min_kbit-$udp_min_kbit-$ssh_min_kbit] rest_max_kbit=$[$UPSTREAM*$2/100] rest_div_kbit=$[$rest_max_kbit-$ack_min_kbit] burst=$[$UPSTREAM*1024/790] echo "down $DOWNSTREAM" echo "burst $burst" echo "" echo "ut_min $ut_min_kbit" echo "ut_max $ut_max_kbit" echo "" echo "udp_min $udp_min_kbit" echo "udp_max $udp_max_kbit" echo "" echo "ssh_min $ssh_min_kbit" echo "ssh_max $ssh_max_kbit" echo "" echo "ack_min $ack_min_kbit" echo "ack_max $ack_max_kbit" echo "" echo "rest_min $rest_min_kbit" echo "rest_max $rest_max_kbit" echo "rest_div $rest_div_kbit" tc qdisc del dev $DEV root 2> /dev/null > /dev/null tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null tcf qdisc add dev $DEV root handle 200: htb default 99 r2q 100 tcf class add dev $DEV parent 200:0 classid 200:1 htb burst $burst rate ${UPSTREAM}kbit cburst 1400 tcf class add dev $DEV parent 200:1 classid 200:50 htb burst $burst rate ${ut_min_kbit}kbit cburst 80 ceil ${ut_max_kbit}kbit prio 0 tcf class add dev $DEV parent 200:1 classid 200:60 htb burst $burst rate ${udp_min_kbit}kbit cburst 80 ceil ${udp_max_kbit}kbit prio 1 tcf class add dev $DEV parent 200:1 classid 200:20 htb burst $burst rate ${ssh_min_kbit}kbit cburst 140 ceil ${ssh_max_kbit}kbit prio 1 tcf class add dev $DEV parent 200:1 classid 200:2 htb burst $burst rate ${rest_min_kbit}kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 2 tcf class add dev $DEV parent 200:2 classid 200:10 htb burst $burst rate ${ack_min_kbit}kbit cburst 80 ceil ${ack_max_kbit}kbit prio 2 tcf class add dev $DEV parent 200:2 classid 200:30 htb burst $burst rate $[$rest_div_kbit*20/(20+1+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 tcf class add dev $DEV parent 200:2 classid 200:40 htb burst $burst rate $[$rest_div_kbit* 1/(20+1+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 tcf class add dev $DEV parent 200:2 classid 200:99 htb burst $burst rate $[$rest_div_kbit*20/(20+1+20)]kbit cburst 1000 ceil ${rest_max_kbit}kbit prio 3 tcf qdisc add dev $DEV parent 200:50 handle 250: bfifo limit 1000 tcf qdisc add dev $DEV parent 200:60 handle 260: bfifo limit 1000 tcf qdisc add dev $DEV parent 200:10 handle 210: sfq perturb 10 tcf qdisc add dev $DEV parent 200:20 handle 220: sfq perturb 10 tcf qdisc add dev $DEV parent 200:30 handle 230: sfq perturb 10 tcf qdisc add dev $DEV parent 200:40 handle 240: sfq perturb 20 tcf qdisc add dev $DEV parent 200:99 handle 299: sfq perturb 10 tcf qdisc add dev $DEV handle ffff: ingress # in my empirical tests I found that ssh consumes upstream at most 6kB/s, which is ~50kbit # filters # 250 for ut # 260 for other udp traffic # 220 for ssh & telnet & irc [max 50kbit/s] # 210 for tcp syns [max 3/sec], acks & icmp # 230 for www # 240 for dc # 299 for rest icmp_match=" match ip protocol 1 0xff" tcp_match=" match ip protocol 6 0xff" udp_match=" match ip protocol 17 0xff" # ff == first fragment == fragment offset=0 ipff_match=" match u16 0 0x1fff at 6" icmpff_match=" $icmp_match $ipff_match" tcpff_match=" $tcp_match $ipff_match" udpff_match=" $udp_match $ipff_match" ssh_smatch=" $tcpff_match match ip sport 22 0xffff" ssh_dmatch=" $tcpff_match match ip dport 22 0xffff" telnet_smatch=" $tcpff_match match ip sport 23 0xffff" telnet_dmatch=" $tcpff_match match ip dport 23 0xffff" irc_smatch=" $tcpff_match match ip sport 6667 0xfff8" irc_dmatch=" $tcpff_match match ip dport 6667 0xfff8" www_smatch=" $tcpff_match match ip sport 80 0xffff" www_dmatch=" $tcpff_match match ip dport 80 0xffff" dch_smatch=" $tcpff_match match ip sport 411 0xffff" dch_dmatch=" $tcpff_match match ip dport 411 0xffff" dcho_smatch=" $tcpff_match match ip sport 4766 0xffff" dcho_dmatch=" $tcpff_match match ip dport 4766 0xffff" dcc1_smatch=" $tcpff_match match ip sport 412 0xffff" dcc1_dmatch=" $tcpff_match match ip dport 412 0xffff" dcc2_smatch=" $tcpff_match match ip sport 1412 0xffff" dcc2_dmatch=" $tcpff_match match ip dport 1412 0xffff" #tmp_smatch=" $tcpff_match match ip sport 8002 0xffff" #tmp_dmatch=" $tcpff_match match ip dport 8002 0xffff" ut_smatch=" $udpff_match match ip sport 7777 0xff00" ut_dmatch=" $udpff_match match ip dport 7777 0xfc00" ihl20_match=" match u8 0x05 0x0f at 0" lt64_match=" match u16 0x0000 0xffc0 at 2" tcpackbit_match="match u8 0x10 0xff at 33" tcpsynbit_match="match u8 0x02 0x0f at 33" tos_maxspeed=" match ip tos 0x08 0xf8" tos_mindelay=" match ip tos 0x10 0xf8" tcpack_match=" $tcpff_match $ihl20_match $lt64_match $tcpackbit_match" tcpsyn_match=" $tcpff_match $lt64_match $tcpsynbit_match" any_match=" match u8 0 0 at 0" ################################################################## # for egress: # s == server, d == client tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ut_dmatch flowid 200:50 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ut_smatch flowid 200:50 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $udp_match flowid 200:60 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ssh_smatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ssh_dmatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $telnet_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $telnet_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $irc_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $irc_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $icmp_match flowid 200:10 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $tcpack_match flowid 200:10 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $tcpsyn_match police rate 1kbit burst 40 mtu 9k continue flowid 200:10 # this rule matches only 3 syns/sec tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $www_dmatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dch_dmatch flowid 200:40 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcho_dmatch flowid 200:40 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcc1_dmatch flowid 200:40 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcc2_dmatch flowid 200:40 ################################################################## # for ingress: # d == server, s == client # anti-spam for our web server tcf filter add dev $DEV parent ffff: protocol ip prio 10 u32 $www_dmatch police rate 10kbit burst 20kbit drop flowid :1 # anti-synflood (requires iptables rule in chain PREROUTING, table mangle) tcf filter add dev $DEV parent ffff: protocol ip prio 50 handle 1 fw police rate 1kbit maxburst 40 mtu 9k drop flowid :1 # downstream limit a little below # not needed for me right now.. #tcf filter add dev $DEV parent ffff: protocol ip prio 59 u32 $tcpack_match police rate 10kbit maxburst 1k flowid :1 tcf filter add dev $DEV parent ffff: protocol ip prio 60 u32 $tcp_match police rate ${DOWNSTREAM}kbit maxburst 10k drop flowid :1 #217.215.22.2