#!/bin/bash
#
# Written by Dan Singletary (8/7/02)
#
# Configuration options for myshaper:
# DEV - set to ethX that connects to DSL/Cable Modem
# RATEUP - set this to slightly lower than your
# outbound bandwidth on the DSL/Cable Modem.
# I have a 1500/128 DSL line and setting
# RATEUP=90 works well for my 128kbps upstream.
# However, your mileage may vary.
#
# The advantage of using a priority-based queuing discipline is
# that we can specifically choose NOT to drop certain types of packets
# that we place in the higher priority buckets (ssh, telnet, etc). This
# is because packets will always be dequeued from the lowest priority class
# with the stipulation that packets will still be dequeued from every
# class fairly at a minimum rate (in this script, each bucket will deliver
# at least it's fair share of 1/7 of the bandwidth).
#
# Reiterating main points:
# * Dropping a tcp packet on a connection will lead to a slower rate
# of reception for that connection due to the congestion avoidance algorithm.
# * We gain nothing from dropping non-TCP packets. In fact, if they
# were important they would probably be retransmitted anyways so we want to
# try to never drop these packets. This means that saturated TCP connections
# will not negatively effect protocols that don't have a built-in retransmit like TCP.
# Interface device to traffic shape/limit
DEV="eth1:1"
# Interface device to traffic shape/limit in format iptables accepts
IPTDEV="eth1+"
# Uplink rate limit in kbits
RATEUP=1300
# Interface queue depth
QLEN=30
# Interface MTU
MTU=1500
#
# End Configuration Options
#
if [ "$1" = "status" ]
then
echo "[qdisc]"
tc -s qdisc show dev "${DEV}"
echo "[class]"
tc -s class show dev "${DEV}"
echo "[filter]"
tc -s filter show dev "${DEV}"
echo "[iptables]"
iptables -t mangle -L MYSHAPER-OUT -v -x 2> /dev/null
exit
fi
# Reset everything to a known state (cleared)
tc qdisc del dev "${DEV}" root 2> /dev/null > /dev/null
iptables -t mangle -D POSTROUTING -o "${IPTDEV}" -j MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -F MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -X MYSHAPER-OUT 2> /dev/null > /dev/null
if [ "$1" = "stop" ]
then
echo "Shaping removed on ${DEV}."
exit
fi
###########################################################
#
# Outbound Shaping (limits total bandwidth to RATEUP)
# set queue size to give latency of about 2 seconds on low-prio packets
ip link set dev "${DEV}" qlen $QLEN
# changes mtu on the outbound device. Lowering the mtu will result
# in lower latency but will also cause slightly lower throughput due
# to IP and TCP protocol overhead.
ip link set dev "${DEV}" mtu $MTU
# add HTB root qdisc
tc qdisc add dev "${DEV}" root handle 1: htb default 26
# add main rate limit classes
tc class add dev "${DEV}" parent 1: classid 1:1 htb rate ${RATEUP}kbit
# add leaf classes - We grant each class at LEAST it's "fair share" of bandwidth.
# this way no class will ever be starved by another class. Each
# class is also permitted to consume all of the available bandwidth
# if no other classes are in use.
tc class add dev "${DEV}" parent 1:1 classid 1:20 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 0
tc class add dev "${DEV}" parent 1:1 classid 1:21 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 1
tc class add dev "${DEV}" parent 1:1 classid 1:22 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 2
tc class add dev "${DEV}" parent 1:1 classid 1:23 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 3
tc class add dev "${DEV}" parent 1:1 classid 1:24 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 4
tc class add dev "${DEV}" parent 1:1 classid 1:25 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 5
tc class add dev "${DEV}" parent 1:1 classid 1:26 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 6
# attach qdisc to leaf classes - here we at SFQ to each priority class. SFQ insures that
# within each class connections will be treated (almost) fairly.
tc qdisc add dev "${DEV}" parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:21 handle 21: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:22 handle 22: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:23 handle 23: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:24 handle 24: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:25 handle 25: sfq perturb 10
tc qdisc add dev "${DEV}" parent 1:26 handle 26: sfq perturb 10
# filter traffic into classes by fwmark - here we direct traffic into priority class according to
# the fwmark set on the packet (we set fwmark with iptables
# later). Note that above we've set the default priority
# class to 1:26 so unmarked packets (or packets marked with
# unfamiliar IDs) will be defaulted to the lowest priority
# class.
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 22 fw flowid 1:22
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 23 fw flowid 1:23
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 24 fw flowid 1:24
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 25 fw flowid 1:25
tc filter add dev "${DEV}" parent 1:0 prio 0 protocol ip handle 26 fw flowid 1:26
# add MYSHAPER-OUT chain to the mangle table in iptables - this sets up the table we'll use
# to filter and mark packets.
iptables -t mangle -N MYSHAPER-OUT
iptables -t mangle -I POSTROUTING -o "${IPTDEV}" -j MYSHAPER-OUT
# add fwmark entries to classify different types of traffic - Set fwmark from 20-26 according to
# desired class. 20 is highest prio.
iptables -t mangle -A MYSHAPER-OUT -p icmp -j MARK --set-mark 20 # ICMP (ping) - high prio
iptables -t mangle -A MYSHAPER-OUT -p icmp -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp -m length --length :64 -j MARK --set-mark 21 # small packets (probably ACKs)
iptables -t mangle -A MYSHAPER-OUT -p tcp -m length --length :64 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p udp -j MARK --set-mark 21 # UDP eg. DNS name resolution (small packets)
iptables -t mangle -A MYSHAPER-OUT -p udp -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -m length --length :128 -j MARK --set-mark 22 # small remote secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -m length --length :128 -j MARK --set-mark 22 # small local secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport telnet -j MARK --set-mark 22 # telnet (ew...)
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport telnet -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport telnet -j MARK --set-mark 22 # telnet (ew...)
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport telnet -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 5190 -j MARK --set-mark 23 # aol instant messenger
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 5190 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 80 -m length --length :128 -j MARK --set-mark 23 # small HTTP packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 80 -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 443 -m length --length :128 -j MARK --set-mark 23 # small HTTPS packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 443 -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 -m length --length :128 -j MARK --set-mark 23 # small Default for low port traffic
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 -m length --length :128 -j MARK --set-mark 23 # ""
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 -m length --length :128 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p ipv6-crypt -j MARK --set-mark 24 # IPSec - we don't know what the payload is though...
iptables -t mangle -A MYSHAPER-OUT -p ipv6-crypt -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -m length --length 129:512 -j MARK --set-mark 24 # medium remote secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -m length --length 129:512 -j MARK --set-mark 24 # medium local secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 80 -m length --length 129:512 -j MARK --set-mark 24 # medium HTTP packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 80 -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 443 -m length --length 129:512 -j MARK --set-mark 24 # medium HTTPS packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 443 -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 -m length --length 129:512 -j MARK --set-mark 24 # medium low port traffic
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 -m length --length 129:512 -j MARK --set-mark 24 # ""
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 -m length --length 129:512 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport http -j MARK --set-mark 25 # local web server
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport http -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport https -j MARK --set-mark 25 # local web server
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport https -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport http -j MARK --set-mark 25 # Remote web server
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport http -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport https -j MARK --set-mark 25 # Remote web server
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport https -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -j MARK --set-mark 26 # large remote secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -j MARK --set-mark 26 # large local secure shell packets
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -j RETURN
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 20 -j MARK --set-mark 26 # ftp-data port, low prio
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 20 -j RETURN
iptables -t mangle -A MYSHAPER-OUT -m mark --mark 0 -j MARK --set-mark 26 # redundant- mark any unmarked packets as 26 (low prio)
# Done with outbound shaping
#
####################################################
echo "Outbound shaping added to ${DEV}. Rate: ${RATEUP}Kbit/sec."