How to throttle speed per client based on data usage?

Hi, all!

I'm on a fairly tight monthly quota of 300GB that I and my brother manage to devour within 20 days or less. So I decided to set a daily quota limit of 10GB using this iptables quota module script written by @easyteacher

# Set data limit, in GB
QUOTA=$((10 * 1073741824))
# Create a new chain named QUOTA
iptables -N QUOTA
# All traffic (up or down) counts against the quota
iptables -A QUOTA -m quota --quota $QUOTA -j ACCEPT
# Drop WAN traffic to/from overquota hosts
iptables -A QUOTA -j DROP
# Process any WAN traffic to/from your hosts with the chain, including the router itself (like DNS traffic).
iptables -A forwarding_rule -j QUOTA
iptables -A input_wan_rule -j QUOTA
iptables -A output_wan_rule -j QUOTA
0 0 * * * iptables -Z QUOTA & # reset the quota every midnight at 12 a.m.

Now I wonder if it's possible to modify this script so I can separately dedicate a daily quota limit per client using MAC or IP addresses? also I'd like to throttle over-quota clients instead of completely shutting off the pipe on them.

1 Like

Disclaimer: This is not an elegant solution. The traffic shaper is based on the iptables hashlimit module, so it's not so accurate.

The original script remains and it will work under the same conditions - when the global daily quota is reached, the router will block all the traffic from/to Internet.

In the new part, you will be able to add (by IP address) clients with a personal quota. When they reach their daily quota, their Internet access bandwidth will be limited (until the global daily quota is reached).

# Original script 10GB global daily quota
QUOTA=$((10 * 1073741824))
iptables -N QUOTA
iptables -A QUOTA -m quota --quota $QUOTA -j ACCEPT
iptables -A QUOTA -j DROP
iptables -A forwarding_rule -j QUOTA
iptables -A input_wan_rule -j QUOTA
iptables -A output_wan_rule -j QUOTA

# Personal quotas
PERSQUOTA=$((3 * 1073741824)) # Edit as needed
users="192.168.1.11 192.168.1.12 192.168.1.13" #Enter client IP addresses, separated by space
i=1
for user in $users; do
iptables -N QUOTA$i
iptables -I FORWARD -s $user -j QUOTA$i
iptables -I FORWARD -d $user -j QUOTA$i
iptables -A QUOTA$i -m quota --quota $PERSQUOTA -j QUOTA
iptables -A QUOTA$i -m hashlimit --hashlimit-upto 64kb/sec --hashlimit-burst 128kb --hashlimit-name mylimit$i -j QUOTA #Edit the bandwidth limit as needed
iptables -A QUOTA$i -j DROP
let "i+=1"
done

You will need the module iptables-mod-hashlimit installed. Also edit the cron table:

0 0 * * * fw3 restart

3 Likes

Impressive, thank you for your time.

May you please excuse my ignorance as I've some questions...

  1. Is 'Personal quotas' script depending on 'global quota'? as I'm planning to get rid of dropping the entire connection function when exceeding the daily quota.

  2. Can I replicate 'Personal quotas' script so I can dedicate a different quota for each client or that would confuse the system?

  3. How does hashlimit actually work? does it limit download and upload at the same rate? Should I always keep 'hashlimit-burst' as twice as 'hashlimit-upto'?

As for the the cron table, I need to remove this line completely
0 0 * * * iptables -Z QUOTA & and replace it with 0 0 * * * fw3 restart, right?

Thanks again, I really appreciate your help.

Just something to consider, it's no problem to burn through 300 GB/ month while being throttled to 10 MBit/s or less - without even resorting to the really throughput intensive stuff like p2p. For a lot of those things you won't even notice the throttling that much.

If you want to actually feel the barrier, you need to resort to much more severe throttling.

Agreed, 1Mbps would probably work

Yes, but it could be modified. I would suggest you to change the rule iptables -A QUOTA -j DROP to iptables -A QUOTA -j ACCEPT. Thus, when the daily quota is reached the Internet won't stop, and you will be able to monitor the "over quota" traffic at the end of the day.

root@OpenWrt:~# iptables -nvL QUOTA
Chain QUOTA (11 references)
 pkts bytes target     prot opt in     out     source               destination
 116K  105M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            quota: 104857600 bytes
91900   93M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -->exceeded traffic

Yes you can, but pay attention to the variable "i". It is involved in the creation of the chains names. Change its value for each new instance to some higher number to avoid chain name duplication (eg. i=10, i=20...).

The "Pesonal quotas" script counts the traffic in both directions (just like the original one).
The hashlimit rule is part of the same iptables chain, so yes, the limitation is applied to the ingress and egress traffic.

There is no specific formula for that. Check the hashlimit options for clarification. As I said before, the hashlimit module is not accurate. The current parameters in the hashlimit rule lead to the following speed test result:

image

Create a test chain and play with the values until you find the ones, that suit you.

iptables -N TEST
iptables -I FORWARD -s <yourtestiphere> -j TEST
iptables -I FORWARD -d <yourtestiphere> -j TEST
iptables -A TEST -m hashlimit --hashlimit-upto 64kb/sec --hashlimit-burst 128kb --hashlimit-name testlimit -j ACCEPT
iptables -A TEST -j DROP

Right.

1 Like

Very informative, thank you for clearing my doubts. Here's the final result, may you please review it

1 Like

Good tip, thanks! I was planning to drop the connection entirely on overquota clients, but I just decided to show some mercy to not create some openwrt enemies :face_with_symbols_over_mouth:

I've set the limit at 128KB/s, I hope that will be enough only to surf the web.

WARNING: If someone else uses the easyteacher's script and reads this, the firewall rule iptables -A input_wan_rule -j QUOTA should be removed. It counts the traffic to the router itself , but also exposes it to the Internet, neutralizing the wan input chain. I should have seen this earlier...

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.