Thursday, September 8, 2011

ultimate.sh

#!/bin/bash
# ultimate.sh for duron
# Based on Wonder Shaper v1.1a
echo "/usr/sbin/ultimate.sh:  "

# Please read the README before filling out these values.
# Set the following values to somewhat less than your actual download
# and upload speed in kilobits.  Also set the device that is to be shaped.

# Run a speed test from netspeed.stanford.edu with no shaping enabled.
# Multiply the reported rates in Kb/s by ~.95 and enter them here:
# Example: DNLINK=4.76M*.95 = 4522
#          UPLINK=444.26K*.95 = 422
# Run the stanford test again.  Note: stanford uses high ports.
# Tweak during heavy upload so that each affected class has a small backlog but
# as few dropped packets as possible.  Interactive must NEVER backlog!
# If heavy downloads affect uploads, tweak IMQ so there is a small backlog but
# as few dropped packets as possible.
# Watch the logs for "some class has too small rate" even with quantum set.
# Stanford is in class 30; egress rate 36% ceil 92%, ingress rate 57% ceil 92%
# Download w/HTB is plenty (5.2x), don't tweak.
# Upload w/UPLINK=470 -> range 416 - 420 = ~85% of uCEIL.  Try for 90% - 91%.

dCEIL=9740	# Stanford max down with no shaping (best of 3 tests)
DNLINK=9350	# (.95*dCEIL, rounded down)
uCEIL=974	# Stanford max up (best of 3 tests).
UPLINK=952	# Tweak.  (was 470=.95*uCEIL, rounded up)
# Percentages, egress:
# sum(Ie + Ae + Be + Pe) _MUST_ = 100
Ie=7			# Interactive
Ae=50			# Accelerated
Be=36			# Bulk
Pe=7			# Penalized

# Percentages, ingress (IMQ):
# sum(Ii + Ai + Bi) _MUST_ = 100
Ii=5			# Interactive
Ai=38			# Accelerated
Bi=57			# Bulk

IFE=eth1		# Egress NIC; External Interface
IMQ=imq0		# Egress NIC - shape incoming

# Local IPs:
ATJ=`cat /etc/firewall/Duron`

# Remote IPs:
#ADE="216.196.97.0/24"	# adelphia.net
CHS=""	# chsoft.biz
DMF=""	# Diana's
NGUY="74.209.0.80/28"	# Newsguy
#HBED1="62.146.66.160/27" # H+BEDV (antivirus)
#HBED2="217.11.60.0/27"	# H+BEDV (antivirus)
#ISW1="207.178.128.0/24"	# iswest
#ISW2="216.166.71.0/24"	# iswest
#ISW3="216.196.105.0/24"	# iswest (giganews)
LHD1=""	# L. H. Dottie
LHD2=""	# L. H. Dottie
#NEWS=""	# news.chsoft.biz
NSAD="67.21.15.0/24"	# Adelphia dns servers
NSTW="66.75.164.0/24"	# Time Warner dns servers
#QUE1="63.231.95.0/24"	# quest
#QUE2="207.225.159.0/24"	# quest
SC=`cat /etc/firewall/SupportJ`	# Note that ports 5500 and 5900 have priority
#TERA="66.150.105.0/24"	# teranews
WALK=""	# Walker Foods
#YIC=""	# yesican.chsoft.biz

###### EXPLANATION
# See 'INGRESS' below for information about incoming packets.  All of this
# except for that refers to queueing outgoing packets.
#
# Most of what is sent goes out on a randomly selected high SOURCE port 
# ('sport') to a specific DESTINATION port ('dport').  For example, an http 
# request is sent with 'dport' = 80 and 'sport' = random.  Therefore, 'sport'
# specifications are rarely applicable.  The port number is located in the
# packet header and is specified thus:
# "u32 match ip dport PORT# 0xffff" or "u32 match ip sport PORT# 0xffff"
#
# Since shaping means quequeing OUTGOING packets, your IP Address(es) are 
# SOURCEs ('src') and the remote machine's IP Address(es) are DESTINATIONs 
# ('dst') - so, as with 'sport', 'src' specifications are rarely applicable. 
# The IP Address is located in the packet header and is specified thus:
# "u32 match ip src IP-ADDRESS" or "u32 match ip dst IP-ADDRESS"
#
# Read the HOWTO "All the filtering commands you will normally need" for
# protocol information (TCP, UDP, ICMP, GRE, IPSEC).  Also see the TOS and
# ICMP sections below.
######

# Sometimes you may notice low priority OUTGOING traffic slowing down important
# traffic. In that case, the following eLoPrio options may help you:

## * * * * Structure:
## {1} * * * * * IFE DEFINITIONS
## {2} * * * * * EGRESS on IFE (HERE --> INTERNET)
## {3} * * * * * IMQ INGRESS shaping on IFE (HERE <-- INTERNET)

###### {1} External Interface DEFINITIONS:
#			Ports:
# eLoPrioSPORT ('sport')
#	Set this to source ports that should have low priority.  If you have
#	an unimportant webserver on your traffic, set this to 80.
# These go into class 40
#   (some ports        ) 20   21    22 23 25   53  80   113   119  873 
#   (and what they are:) FTPd FTPc  SSH   SMTP DNS HTTP IDENT NNTP Rsync
# 9001 is tor Server, 9030 is tor Directory
# Search 6881 for torrent special handling (1:40)
# Matches FROM me:PORT 
eLoPrioSPORT="8 21 23 67 68 79 110 135 137 138 139 389 445 446 901 1026 1027 1028 1029 1234 5018"

# eHiPrioSPORT ('sport')
# These go into class 20.  SSH and scp are interactive (class 10).
# *** Make sure no eLoPrioSPORTs are duplicated here! ***
# Matches (apparently) nothing.
eHiPrioSPORT="113 119 123 443 563 873 5500 5900"

# eLoPrioDPORT ('dport')
#	Set this to destination ports that should have low priority. 
# The following are from my TARPIT list: 79 135 137 138 139 445 901
# Matches DIR=FROM? remote:PORT
# These go into class 40
eLoPrioDPORT="8 21 23 67 68 79 110 135 137 138 139 389 445 446 901 1026 1027 1028 1029 1234 5018"

# eHiPrioDPORT ('dport')
# *** Make sure no eLoPrioDPORTs are duplicated here! ***  ssh is interactive.
# Matches DIR=FROM? ?:PORT
# These go into class 20
eHiPrioDPORT="113 119 123 443 563 873 5500 5900"

#			IPs / Netmasks:
# Set this to hosts or netmasks in your network that should have low priority.
# Low priority OUTGOING traffic.  You can leave this blank if you want.
# Matches TO REMOTE
# These go into class 40
eLoPrioCIDR_Src=""
#eLoPrioCIDR_Src="$ATJ"

# See EXPLANATION above; these do not need to be here.
# Matches (apparently) nothing.
# These go into class 20
eHiPrioCIDR_Src="$CHS $LHD1 $NGUY $SC $WALK"

# Set this to hosts or netmasks on the internet that should have low priority.
# Matches FROM REMOTE
# These go into class 40
eLoPrioCIDR_Dst="221.0.0.0/8"

# high priority destination netmasks ('dst'):
# Matches DIR? REMOTE:IP
# These go into class 20
eHiPrioCIDR_Dst="$CHS $LHD1 $NGUY $SC $WALK"
###### End External Interface DEFINITIONS

if [ "$1" = "status" ]; then
	echo "Sent on $IFE:"
# 	tc -s filter show dev $IFE
	tc -d qdisc ls dev $IFE
	tc -s qdisc ls dev $IFE
	tc -s class ls dev $IFE
	echo "'rate #bit' means Bytes per Second"
	echo "Received on $IMQ:"
#	tc -s filter show dev $IMQ
	tc -d qdisc ls dev $IMQ
	tc -s qdisc ls dev $IMQ
	tc -s class ls dev $IMQ
	echo "'rate #bit' is meaningless.  Measure by Backlog and Dropped."
	exit
fi

# Clean existing setup, hiding errors
tc qdisc del dev $IFE root	2> /dev/null > /dev/null
tc qdisc del dev $IFE ingress	2> /dev/null > /dev/null
iptables -t mangle -D PREROUTING -i $IFE -j IMQ --todev 0	2>/dev/null > /dev/null
tc qdisc del dev $IMQ root	2> /dev/null > /dev/null
ip link set $IMQ down		2> /dev/null > /dev/null
modprobe -r ipt_IMQ		# iptables
modprobe -r imq			# device
modprobe -r cls_u32
modprobe -r sch_esfq		# requires modified tc
modprobe -r sch_sfq
modprobe -r sch_htb
modprobe -r sch_ingress

if [ "$1" = "stop" ]; then 
	exit
fi

###### {2} uplink (EGRESS) on IFE
# This part shapes on the external interface:  (HERE --> INTERNET)
# Install root HTB, point default traffic to 1:30:
tc qdisc add dev $IFE root handle 1: htb default 30

# Shape everything at $UPLINK speed - this prevents huge queues in your
# DSL modem which destroy latency:
tc class add dev $IFE parent 1: classid 1:1 htb rate ${uCEIL}kbit burst 32k cburst 20k

# High prio (interactive) class 1:10:
tc class add dev $IFE parent 1:1 classid 1:10 htb rate $[Ie*$UPLINK/100]kbit \
   ceil ${uCEIL}kbit burst 32k cburst 20k quantum 1514 prio 1

# Accelerated class 1:20 - the HIPRIO stuff:
tc class add dev $IFE parent 1:1 classid 1:20 htb rate $[Ae*$UPLINK/100]kbit \
   ceil $[96*$uCEIL/100]kbit burst 16k cburst 10k quantum 1514 prio 2

# Bulk & default class 1:30 - gets a low priority:
tc class add dev $IFE parent 1:1 classid 1:30 htb rate $[Be*$UPLINK/100]kbit \
   ceil $[92*$UPLINK/100]kbit burst 8k cburst 5k quantum 1514 prio 3
#   ceil $[Ae*$UPLINK/100]kbit burst 8k cburst 5k quantum 1514 prio 3

# Penalized class 1:40 - the LOPRIO stuff gets the lowest rate and priority:
tc class add dev $IFE parent 1:1 classid 1:40 htb rate $[Pe*$UPLINK/100]kbit \
   ceil $[80*$UPLINK/100]kbit burst 2k quantum 1514 prio 4
#   ceil $[Be*$UPLINK/100]kbit burst 2k quantum 1514 prio 4

# Some get Stochastic Fairness:
# LARTC mailing list indicates that interactive should not be included.  Andy
# Furniss suggests that bulk be the only thing subject to SF.  I set a long
# perturb for accelerated and exclude interactive.
# Increased limit from 64 to reduce # of dropped packets 7Dec07
# 11Dec07: esfq limit must be less than or equal depth; depth max = 1024:
#tc qdisc add dev $IFE parent 1:10 handle 10: esfq limit 64 depth 64 divisor 10 hash classic perturb 20
tc qdisc add dev $IFE parent 1:20 handle 20: esfq limit 256 depth 256 divisor 10 hash classic perturb 99
tc qdisc add dev $IFE parent 1:30 handle 30: esfq limit 1024 depth 1024 divisor 10 hash classic perturb 20
tc qdisc add dev $IFE parent 1:40 handle 40: esfq limit 32 depth 32 divisor 10 hash classic perturb 10

# ARP:
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
   match u16 0x0806 0xffff at -2 flowid 1:40

###### Accelerate (interactive) the following:
# To speed up downloads while an upload is going on, put ACK packets in
# the interactive class 1:10:
# IP header length 0x5 (32 bit words)
# IP total length 0x34 (ACK + 12 bytes of TCP options)
# TCP ACK set (bit 5, offset 33)
# ("at nexthdr+33" = "at 13")

## Match ACK on all TCP packets with the ACK bit set:
## Caveat!: This can match packets up to 64K; don't do it.  Match small.
#tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
#    match ip protocol 6 0xff \
#    match u8 0x10 0xff at nexthdr+13 \
#    flowid 1:10

# Match TCP packets smaller than 128 bytes:
# Because of the mask, can only match powers of 2 (32, 64, 128...)
# 0xfff8 - 8
# 0xfff0 - 16
# 0xffe0 - 32
# 0xffc0 - 64
# 0xff80 - 128
# Remarked out ACK, normally 5th line:  match u8 0x10 0xff at 33 \
# "match u8 0x05 0x0f at 0" makes sure the IP header is 20 bytes.
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
    match ip protocol 6 0xff \
    match u8 0x05 0x0f at 0 \
    match u16 0x0000 0xff80 at 2 \
    flowid 1:10

# SSH and scp are interactive.
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
    match ip dport 22 0xffff flowid 1:10
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
    match ip sport 22 0xffff flowid 1:10

# dns is interactive:
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
    match ip dport 53 0xffff flowid 1:10
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
    match ip sport 53 0xffff flowid 1:10

###### Some traffic is preferred, so in our class 1:20:
for a in $eHiPrioDPORT; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip dport $a 0xffff flowid 1:20
done
for a in $eHiPrioSPORT; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip sport $a 0xffff flowid 1:20
done
for a in $eHiPrioCIDR_Src; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip src $a flowid 1:20
done
for a in $eHiPrioCIDR_Dst; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip dst $a flowid 1:20
done

###### Give these short shrift:
# Penalized traffic suffers a worse fate in our slowest class 1:40:
# Special for torrents ports 6880-6887:
# The mask determines the number of ports: ffff=1 fffe=2 fffc=4 fff8=8 fff0=16
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
   match ip dport 6881 0xfff8 flowid 1:40
tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
   match ip sport 6881 0xfff8 flowid 1:40
for a in $eLoPrioDPORT; do
	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip dport $a 0xffff flowid 1:40
done
for a in $eLoPrioSPORT; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip sport $a 0xffff flowid 1:40
done
for a in $eLoPrioCIDR_Src; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip src $a flowid 1:40
done
for a in $eLoPrioCIDR_Dst; do
 	tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
	   match ip dst $a flowid 1:40
done
if [ -f /etc/firewall/shitlist ]; then
   while read SLIST; do
      SLIST=$(echo "$SLIST" | awk '{print $1}')
      tc filter add dev $IFE parent 1: protocol all prio 5 u32 \
         match ip dst $SLIST flowid 1:40
   done <-- INTERNET)
modprobe imq numdevs=1
# Since class 1:10 uses the default pfifo_fast, we need to give it txqueuelen
# packets because pfifo_fast drops incoming packets when the queue fills up:
ip link set $IMQ up txqueuelen 1024 mtu 1500

# Install root HTB, point default traffic to 1:30:
tc qdisc add dev $IMQ root handle 1: htb default 30

# Shape everything at DNLINK speed:
# Root class
tc class add dev $IMQ parent 1: classid 1:1 htb rate ${dCEIL}kbit burst 32k \
  cburst 20k quantum 1500

# High priority (interactive) class 1:10
tc class add dev $IMQ parent 1:1 classid 1:10 htb rate $[Ii*$DNLINK/100]kbit \
   ceil ${dCEIL}kbit burst 32k cburst 20k quantum 1500 prio 1

# Accelerated class 1:20 
tc class add dev $IMQ parent 1:1 classid 1:20 htb rate $[Ai*$DNLINK/100]kbit \
   ceil $[96*$dCEIL/100]kbit burst 16k cburst 10k quantum 1500 prio 2

# Bulk & default class 1:30
tc class add dev $IMQ parent 1:1 classid 1:30 htb rate $[Bi*$DNLINK/100]kbit \
   ceil $[92*$dCEIL/100]kbit burst 8k cburst 5k quantum 1500 prio 3

# Stochastic Fairness
tc qdisc add dev $IMQ parent 1:20 handle 20: esfq limit 1024 depth 1024 divisor 10 hash dst perturb 99 
tc qdisc add dev $IMQ parent 1:30 handle 30: esfq limit 768 depth 768 divisor 10 hash dst perturb 20 

# Interactive ports:
IMQint="22 53 5500 5900"

# Accelerated ports:
IMQacc="80 113 123 443 873 6502"

for a in $IMQint; do
   tc filter add dev $IMQ parent 1: protocol all prio 5 u32 match \
      ip dport $a 0xffff flowid 1:10
   tc filter add dev $IMQ parent 1: protocol all prio 5 u32 match \
      ip sport $a 0xffff flowid 1:10
done

for a in $IMQacc; do
   tc filter add dev $IMQ parent 1: protocol all prio 5 u32 match \
      ip dport $a 0xffff flowid 1:20
   tc filter add dev $IMQ parent 1: protocol all prio 5 u32 match \
      ip sport $a 0xffff flowid 1:20
done

# Not needed because 1:30 is default:
## Match everything else: 
#tc filter add dev $IMQ parent 1: protocol all prio 5 u32 match u32 0 0 flowid 1:30

iptables -t mangle -I PREROUTING -i $IFE -j IMQ --todev 0

# Done ultimate.sh