How to limit bandwidth per IP and be unfair on purpose

Hi,

I would like to limit bandwidth for some devices. I am aware that SQM default take care of fairness usage so that no single device take over the whole network. But this is not I am looking for. I want to on purpose being unfair and limit internet usage for some devices.

For the why: eg: limit internet to non-video and stream based usage.

What is the best approach ? Can SQM do unfair traffic shaping per IP (or MAC) ? iptables with some packet drop rate ?

Currently using OpenWrt 21.02.2 on ASUS RT-AC58U

https://forum.openwrt.org/search?q=bandwidth%20limit%20per%20ip

https://forum.openwrt.org/search?q=bandwidth%20limit%20per%20ip

Yup. Been there. If you look at the search results:

  • Use luci-app-nft-qos: obsolete package that don't work anymore. I installed it, configured and nothing happe (yes, I rebooted the router)
  • Use SQM to limit a whole interface : I tried that and it works. But I am looking to do per IP
  • Most of the post are deadend

Yes and no. SQM is both a set of scripts implementing what we consider sane and generally useful traffic-sharing policies and a framework to handle such scrpits to play nicely with OpenWrt. The former is not helping, but the latter is something you might be able to harness. If you want to write your own script simple.qos is a decent starting point, just ann more specific HTB instances and filters (and AQMs) for each device to be throttled. Keep in mind though that for the default ifb-ingress on WAN qdisc internal IP addresses are not available, so you might want to instantiate your throttle-me-this script on the LAN side instead.

Definitely not the best approach, but it can be used if you don't have high expectations.

opkg update; opkg install iptables-mod-hashlimit
iptables -A forwarding_rule -d 192.168.1.100/32 -m hashlimit --hashlimit-above 128kb/sec --hashlimit-burst 256kb --hashlimit-name user100dl --hashlimit-mode dstip -j DROP
iptables -A forwarding_rule -d 192.168.1.101/32 -m hashlimit --hashlimit-above 128kb/sec --hashlimit-burst 256kb --hashlimit-name user101dl --hashlimit-mode dstip -j DROP
iptables -A forwarding_rule -d 192.168.1.102/32 -m hashlimit --hashlimit-above 128kb/sec --hashlimit-burst 256kb --hashlimit-name user102dl --hashlimit-mode dstip -j DROP

The limits aren't precise at all, so you'll have to play around with the values if you decide to use it.
These rules only limit the download speed.

https://manpages.debian.org/jessie/iptables/iptables-extensions.8.en.html#hashlimit

The openNDS package can do this, but usually via some login, where upload and download quotas and rates are specified.
But if you have a list of mac addresses to be restricted you can add a dnsmasq dhcpscript option that runs a custom script whenever a device is allocated an ip address. This will authenticate devices on the list with specified quotas and rates, and devices not on the list getting full access or some default predefined allocation.

iptables -A forwarding_rule -d 192.168.1.100/32 -m hashlimit --hashlimit-above 128kb/sec --hashlimit-burst 256kb --hashlimit-name user100dl --hashlimit-mode dstip -j DROP

Where should I put this rule ?
I put it in the firewall.user ( Firewall - Custom Rules) and restart the firewall with /etc/init.d/firewall restart
But the speedtest show that there is no limit on the device.

Edit:
I can see that the rule been added with iptables -L:

Chain forwarding_rule (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             phone.lan        limit: above 50kb/s burst 100kb mode dstip

Yes, it should be inserted into /etc/firewall.user, but run it from the command line first to make sure it doesn't return errors.

Check the rule for hits running iptables -nvL forwarding_rule

root@OpenWrt:~# iptables -nvL forwarding_rule
Chain forwarding_rule (1 references)
 pkts bytes target     prot opt in     out     source               destination
19461 1523K DROP       all  --  *      *       0.0.0.0/0            192.168.92.85        limit: above 128kb/s burst 256kb mode dstip

image

root@asus:/etc/config# iptables -L 
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */
input_rule  all  --  anywhere             anywhere             /* !fw3: Custom input rule chain */
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED /* !fw3 */
syn_flood  tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN /* !fw3 */
zone_lan_input  all  --  anywhere             anywhere             /* !fw3 */
zone_wan_input  all  --  anywhere             anywhere             /* !fw3 */
zone_guestZone_input  all  --  anywhere             anywhere             /* !fw3 */
zone_trusted_input  all  --  anywhere             anywhere             /* !fw3 */

Chain FORWARD (policy DROP)
target     prot opt source               destination         
forwarding_rule  all  --  anywhere             anywhere             /* !fw3: Custom forwarding rule chain */
FLOWOFFLOAD  all  --  anywhere             anywhere             /* !fw3: Traffic offloading */ ctstate RELATED,ESTABLISHED FLOWOFFLOAD
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED /* !fw3 */
zone_lan_forward  all  --  anywhere             anywhere             /* !fw3 */
zone_wan_forward  all  --  anywhere             anywhere             /* !fw3 */
zone_guestZone_forward  all  --  anywhere             anywhere             /* !fw3 */
zone_trusted_forward  all  --  anywhere             anywhere             /* !fw3 */
reject     all  --  anywhere             anywhere             /* !fw3 */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */
output_rule  all  --  anywhere             anywhere             /* !fw3: Custom output rule chain */
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED /* !fw3 */
zone_lan_output  all  --  anywhere             anywhere             /* !fw3 */
zone_wan_output  all  --  anywhere             anywhere             /* !fw3 */
zone_guestZone_output  all  --  anywhere             anywhere             /* !fw3 */
zone_trusted_output  all  --  anywhere             anywhere             /* !fw3 */

Chain forwarding_guestZone_rule (1 references)
target     prot opt source               destination         

Chain forwarding_lan_rule (1 references)
target     prot opt source               destination         

Chain forwarding_rule (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             phone.lan        limit: above 50kb/s burst 100kb mode dstip

Chain forwarding_trusted_rule (1 references)
target     prot opt source               destination         

Chain forwarding_wan_rule (1 references)
target     prot opt source               destination         

Chain input_guestZone_rule (1 references)
target     prot opt source               destination         

Chain input_lan_rule (1 references)
target     prot opt source               destination         

Chain input_rule (1 references)
target     prot opt source               destination         

Chain input_trusted_rule (1 references)
target     prot opt source               destination         

Chain input_wan_rule (1 references)
target     prot opt source               destination         

Chain output_guestZone_rule (1 references)
target     prot opt source               destination         

Chain output_lan_rule (1 references)
target     prot opt source               destination         

Chain output_rule (1 references)
target     prot opt source               destination         

Chain output_trusted_rule (1 references)
target     prot opt source               destination         

Chain output_wan_rule (1 references)
target     prot opt source               destination         

Chain reject (6 references)
target     prot opt source               destination         
REJECT     tcp  --  anywhere             anywhere             /* !fw3 */ reject-with tcp-reset
REJECT     all  --  anywhere             anywhere             /* !fw3 */ reject-with icmp-port-unreachable

Chain syn_flood (1 references)
target     prot opt source               destination         
RETURN     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN limit: avg 25/sec burst 50 /* !fw3 */
DROP       all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_dest_ACCEPT (3 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_dest_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_forward (1 references)
target     prot opt source               destination         
forwarding_guestZone_rule  all  --  anywhere             anywhere             /* !fw3: Custom guestZone forwarding rule chain */
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone guestZone to wan forwarding policy */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port forwards */
zone_guestZone_dest_REJECT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_input (1 references)
target     prot opt source               destination         
input_guestZone_rule  all  --  anywhere             anywhere             /* !fw3: Custom guestZone input rule chain */
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain /* !fw3: guestDnsDhcp */
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:bootps /* !fw3: guestDnsDhcp */
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:bootpc /* !fw3: guestDnsDhcp */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain /* !fw3: guestDnsDhcp */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootps /* !fw3: guestDnsDhcp */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootpc /* !fw3: guestDnsDhcp */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port redirections */
zone_guestZone_src_REJECT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_output (1 references)
target     prot opt source               destination         
output_guestZone_rule  all  --  anywhere             anywhere             /* !fw3: Custom guestZone output rule chain */
zone_guestZone_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_guestZone_src_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_lan_dest_ACCEPT (5 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_lan_forward (1 references)
target     prot opt source               destination         
forwarding_lan_rule  all  --  anywhere             anywhere             /* !fw3: Custom lan forwarding rule chain */
zone_trusted_dest_ACCEPT  tcp  --  anywhere             base-address.mcast.net/4  /* !fw3: multicast */
zone_trusted_dest_ACCEPT  udp  --  anywhere             base-address.mcast.net/4  /* !fw3: multicast */
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone lan to wan forwarding policy */
zone_guestZone_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone lan to guestZone forwarding policy */
zone_trusted_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone lan to trusted forwarding policy */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port forwards */
zone_lan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_lan_input (1 references)
target     prot opt source               destination         
input_lan_rule  all  --  anywhere             anywhere             /* !fw3: Custom lan input rule chain */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port redirections */
zone_lan_src_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_lan_output (1 references)
target     prot opt source               destination         
output_lan_rule  all  --  anywhere             anywhere             /* !fw3: Custom lan output rule chain */
zone_lan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_lan_src_ACCEPT (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate NEW,UNTRACKED /* !fw3 */

Chain zone_trusted_dest_ACCEPT (4 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_trusted_dest_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_trusted_forward (1 references)
target     prot opt source               destination         
forwarding_trusted_rule  all  --  anywhere             anywhere             /* !fw3: Custom trusted forwarding rule chain */
zone_guestZone_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone trusted to guestZone forwarding policy */
zone_lan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone trusted to lan forwarding policy */
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3: Zone trusted to wan forwarding policy */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port forwards */
zone_trusted_dest_REJECT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_trusted_input (1 references)
target     prot opt source               destination         
input_trusted_rule  all  --  anywhere             anywhere             /* !fw3: Custom trusted input rule chain */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port redirections */
zone_trusted_src_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_trusted_output (1 references)
target     prot opt source               destination         
output_trusted_rule  all  --  anywhere             anywhere             /* !fw3: Custom trusted output rule chain */
zone_trusted_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_trusted_src_ACCEPT (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate NEW,UNTRACKED /* !fw3 */

Chain zone_wan_dest_ACCEPT (4 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             ctstate INVALID /* !fw3: Prevent NAT leakage */
ACCEPT     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_wan_dest_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere             /* !fw3 */

Chain zone_wan_forward (1 references)
target     prot opt source               destination         
forwarding_wan_rule  all  --  anywhere             anywhere             /* !fw3: Custom wan forwarding rule chain */
zone_lan_dest_ACCEPT  esp  --  anywhere             anywhere             /* !fw3: Allow-IPSec-ESP */
zone_lan_dest_ACCEPT  udp  --  anywhere             anywhere             udp dpt:isakmp /* !fw3: Allow-ISAKMP */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port forwards */
zone_wan_dest_REJECT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_wan_input (1 references)
target     prot opt source               destination         
input_wan_rule  all  --  anywhere             anywhere             /* !fw3: Custom wan input rule chain */
ACCEPT     udp  --  anywhere             anywhere             udp dpt:bootpc /* !fw3: Allow-DHCP-Renew */
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request /* !fw3: Allow-Ping */
ACCEPT     igmp --  anywhere             anywhere             /* !fw3: Allow-IGMP */
ACCEPT     all  --  anywhere             anywhere             ctstate DNAT /* !fw3: Accept port redirections */
zone_wan_src_REJECT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_wan_output (1 references)
target     prot opt source               destination         
output_wan_rule  all  --  anywhere             anywhere             /* !fw3: Custom wan output rule chain */
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             /* !fw3 */

Chain zone_wan_src_REJECT (1 references)
target     prot opt source               destination         
reject     all  --  anywhere             anywhere             /* !fw3 */

But nothing seems to be dropped:

root@asus:/etc/config# iptables -nvL forwarding_rule
Chain forwarding_rule (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            192.168.1.10         limit: above 50kb/s burst 100kb mode dstip

Is it because I have multiple interface ? I have the right IP I am sure.

No, the rule is created at the beginning of the FORWARD chain (before any other rules) and works based on the IP address.

Try

iptables -I FORWARD ...

but it shouldn't make a difference.

Tried with a second device:

iptables -I FORWARD -d 192.168.1.10/32 -m hashlimit --hashlimit-above 50kb/sec --hashlimit-burst 100kb --hashlimit-name user10dl --hashlimit-mode dstip -j DROP
iptables -I FORWARD -d 192.168.1.222/32 -m hashlimit --hashlimit-above 50kb/sec --hashlimit-burst 100kb --hashlimit-name user22dl --hashlimit-mode dstip -j DROP

But no luck :

root@asus:/etc/config# iptables -nvL FORWARD
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            192.168.1.222        limit: above 50kb/s burst 100kb mode dstip
    0     0 DROP       all  --  *      *       0.0.0.0/0            192.168.1.10         limit: above 50kb/s burst 100kb mode dstip
  110 22509 forwarding_rule  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Custom forwarding rule chain */
   38  4288 FLOWOFFLOAD  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Traffic offloading */ ctstate RELATED,ESTABLISHED FLOWOFFLOAD
   38  4288 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED /* !fw3 */
   72 18221 zone_lan_forward  all  --  br-lan *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_wan_forward  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_guestZone_forward  all  --  wlan0-2 *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_trusted_forward  all  --  br-trusted *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 reject     all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */

Edit :

root@asus:/etc/config# iptables --version
iptables v1.8.7 (legacy)

Run these commands.

fw3 restart
iptables -I FORWARD -d 192.168.1.10/32 -j DROP
iptables -I FORWARD -s 192.168.1.10/32 -j DROP
iptables -I FORWARD -d 192.168.1.10/32 -m hashlimit --hashlimit-upto 50kb/sec --hashlimit-burst 100kb --hashlimit-name user10dl --hashlimit-mode dstip -j ACCEPT
iptables -I FORWARD -s 192.168.1.10/32 -m hashlimit --hashlimit-upto 50kb/sec --hashlimit-burst 100kb --hashlimit-name user10dl --hashlimit-mode srcip -j ACCEPT

If you still don't see any hits (and the IP address is correct), the traffic doesn't traverse the FORWARD chain (like if it's a dumbAP)

Working !!
Bandwidth limited !

root@asus:/etc/config# iptables -nvL FORWARD
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 2007  191K ACCEPT     all  --  *      *       192.168.1.10         0.0.0.0/0            limit: up to 50kb/s burst 100kb mode srcip
 1906  860K ACCEPT     all  --  *      *       0.0.0.0/0            192.168.1.10         limit: up to 50kb/s burst 100kb mode dstip
    0     0 DROP       all  --  *      *       192.168.1.10         0.0.0.0/0           
    0     0 DROP       all  --  *      *       0.0.0.0/0            192.168.1.10        
  492 81347 forwarding_rule  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Custom forwarding rule chain */
  164 23012 FLOWOFFLOAD  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Traffic offloading */ ctstate RELATED,ESTABLISHED FLOWOFFLOAD
  164 23012 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED /* !fw3 */
  327 58252 zone_lan_forward  all  --  br-lan *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_wan_forward  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    1    83 zone_guestZone_forward  all  --  wlan0-2 *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_trusted_forward  all  --  br-trusted *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 reject     all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */

Limiting ACCEPT works. But not dropping ?
What happening to the packet that are above the accept threshold ?? I don't see them in the Drop rule ....

The logical explanation - no such packets.
This would also explain why you don't see any dropped packets using the opposite approach.
Try lowering the limits even more.

BTW, I have made a copy/paste error.
Change --hashlimit-name of the second rule (limiting uploads).

iptables -I FORWARD -s 192.168.1.10/32 -m hashlimit --hashlimit-upto 50kb/sec --hashlimit-burst 100kb --hashlimit-name user10upl --hashlimit-mode srcip -j ACCEPT

So I tried DROP with rate down to 1kb/s : not working. My phone just go full bandwidth.

Play a bit around and found that when using the approach ACCEPT with limited rate, the DROP rule is not needed. The below setup will limit the bandwidth:

root@asus:~# iptables -nvL FORWARD
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 2056  893K ACCEPT     all  --  *      *       0.0.0.0/0            192.168.1.10         limit: up to 600kb/s burst 1mb mode dstip
 2819  250K ACCEPT     all  --  *      *       192.168.1.10         0.0.0.0/0            limit: up to 600kb/s burst 1mb mode srcip
  603 99569 forwarding_rule  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Custom forwarding rule chain */
  329 52907 FLOWOFFLOAD  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3: Traffic offloading */ ctstate RELATED,ESTABLISHED FLOWOFFLOAD
  329 52907 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED /* !fw3 */
  270 46451 zone_lan_forward  all  --  br-lan *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_wan_forward  all  --  eth1   *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    4   211 zone_guestZone_forward  all  --  wlan0-2 *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 zone_trusted_forward  all  --  br-trusted *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */
    0     0 reject     all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* !fw3 */

So only ACCEPT matter. Which kind of explain why setting a DROP rate do not have any effect.

But why the behavior is reversed compare to @pavelgl ??

And also both -s and -d ACCEPT rule is needed. If it's only one of them, the bandwidth is not limited.