How to identify download traffic using iptables
Solution 1:
The iptables modules connbytes, connlimit and length can be used to identify downloads. Here the setup is use:
#Mark downloads
$IPT -t mangle -N BULKCONN
#Small packet is probably interactive or flow control
$IPT -t mangle -A BULKCONN -m length --length 0:500 -j RETURN
#Small packet connections: multi purpose (don't harm since not maxed out)
$IPT -t mangle -A BULKCONN -m connbytes --connbytes 0:250 --connbytes-dir both --connbytes-mode avgpkt -j RETURN
#After one megabyte a connection is considered a download
$IPT -t mangle -A BULKCONN -m connbytes --connbytes 1048576: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark 6
$IPT -t mangle -A BULKCONN -j RETURN
$IPT -t mangle -A PREROUTING -i eth1 -j BULKCONN
I use queuing disciplines to prioritize downloads and other traffic.
About sending through another link: I am not ready to answer this, but it would be done with iproute2 (assuming you mean another IP link). However it will only work downstream, since you can not control where upstream traffic reaches you.
Solution 2:
I was inspired by @Ganwell solution to this, and managed to solve this on top of adding in a tc
classful traffic shaping. I blogged about this solution in my personal wiki: https://giki.wiki/@nubela/Software-Engineering/Per-Connection-Throttling
Here's my solution to this question with an actual shell script:
#!/bin/sh
dev=eth0
ip_port=3002
rate_limit=512kbit
rate_ceil=1024kbit
htb_class=10
max_byte=10485760
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
if [ "$1" = "enable" ]; then
echo "enabling rate limits"
tc qdisc del dev $dev root > /dev/null 2>&1
tc qdisc add dev $dev root handle 1: htb
tc class add dev $dev parent 1: classid 1:$htb_class htb rate $rate_limit ceil $rate_ceil
tc filter add dev $dev parent 1: prio 0 protocol ip handle $htb_class fw flowid 1:$htb_class
#iptables -t mangle -A OUTPUT -p tcp --sport $ip_port -j MARK --set-mark $htb_class
# small packet is probably interactive or flow control
iptables -t mangle -A OUTPUT -p tcp --sport $ip_port -m length --length 0:500 -j RETURN
# small packet connections: multi purpose (don't harm since not maxed out)
iptables -t mangle -A OUTPUT -p tcp --sport $ip_port -m connbytes --connbytes 0:250 --connbytes-dir both --connbytes-mode avgpkt -j RETURN
#after 10 megabyte a connection is considered a download
iptables -t mangle -A OUTPUT -p tcp --sport $ip_port -m connbytes --connbytes $max_byte: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark $htb_class
iptables -t mangle -A OUTPUT -j RETURN
elif [ "$1" = "disable" ]; then
echo "disabling rate limits"
tc qdisc del dev $dev root > /dev/null 2>&1
iptables -t mangle -F
iptables -t mangle -X
elif [ "$1" = "show" ]; then
tc qdisc show dev $dev
tc class show dev $dev
tc filter show dev $dev
iptables -t mangle -vnL INPUT
iptables -t mangle -vnL OUTPUT
else
echo "invalid arg $1"
fi