• Welcome to Valhalla Legends Archive.
 

Limiting Bandwith

Started by Forged, August 19, 2005, 10:34 PM

Previous topic - Next topic

Forged

I want to write a program that limits the upload/download speed of a home computer.  I have found a few programs that do it, but I don't want a standalone program just a method of doing so.  Google has proven almost useless, it shows you ways of doing it that are modem specific but nothing generic.

I am not writing any kind of malware if that is what you are thinking.
QuoteI wish my grass was Goth so it would cut itself

Arta

I think you'd need to write some kind of driver to do that. Have you read about NDIS?

iago

On a linux computer, you can do, for example, this:

#!/bin/bash

# The array of what we're limiting
actions=(
22,20kbps
#8001,20kbps
)

# Set up our program variables
IPTABLES="/usr/sbin/iptables"
TC="/sbin/tc"

if ! [ $1 ]; then
        echo "specify a device!"
        exit 1
fi

devs="$1";

# count commas...
lastaction=`echo ${actions[*]} | tr \, '\n' | wc -l`

# extra comma and array starts at zero...
let lastaction-=2

stop-tc() {

        for dev in $devs; do
                if ${TC} qdisc del dev $dev root &> /dev/null; then
                        echo "tc has now stopped for $dev"
                fi
        done
}

# Flush the whole mangle table.
${IPTABLES} -t mangle -F
if ! [ $? = "0" ]; then echo iptables failed at line $LINENO; exit 1; fi

# stop traffic control completely.
stop-tc $devs

# set up basic traffic control magic

for dev in $devs; do
        ${TC} qdisc add dev $dev root handle 1: htb default 10
        if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

        ${TC} class add dev $dev parent 1:  classid 1:1  htb rate 1mbit burst 15k
        if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

        ${TC} class add dev $dev parent 1:1 classid 1:2 htb rate 1mbit burst 15k
        if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

        ${TC} qdisc add dev $dev parent 1:2 handle  2:  sfq perturb 10
        if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi
done                                                                     

# the mark number and also the queue number.  Must start at 3 so it doesn't
# collide with ones we've already set up.
n=3

# index into the speeds array
index=0

for m in `seq 0 $lastaction`; do

  port=`echo ${actions[$m]} | cut -d\, -f1`
  speed=`echo ${actions[$m]} | cut -d\, -f2`

  echo Packets headed for port $port will be shaped to $speed.

  ${IPTABLES} -t mangle -A POSTROUTING --protocol tcp --source-port $port      -j MARK --set-mark $n
  ${IPTABLES} -t mangle -A POSTROUTING --protocol udp --source-port $port      -j MARK --set-mark $n
  ${IPTABLES} -t mangle -A POSTROUTING --protocol tcp --destination-port $port -j MARK --set-mark $n
  ${IPTABLES} -t mangle -A POSTROUTING --protocol udp --destination-port $port -j MARK --set-mark $n

  if ! [ $? = "0" ]; then echo iptables failed at line $LINENO; exit 1; fi

  for dev in $devs; do
          # per class traffic control black magic
          ${TC} class  add dev $dev parent 1:1  classid 1:$n htb rate $speed burst 1k
          if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

          ${TC} qdisc  add dev $dev parent 1:$n handle  $n:  sfq perturb 10
          if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi

          ${TC} filter add dev $dev protocol ip parent 1:0 prio 1 handle $n fw flowid 1:$n
          if ! [ $? = "0" ]; then echo tc failed at line $LINENO; exit 1; fi
  done

  let n++
  let index++
done


That could be modified fairly easily to limit by ip instead of by port. 

Or, if you have netfilter installed in the kernel, you can filter by application.  Which is pretty cool. 
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*