I recently got my Raspberry Pi to act as a WiFi Router with shaping by using hostapd, tc, and iptables together to broadcast as an Access Point, apply shaping rules, and apply packet marking respectively.
This can be done on any device with 2 NICs but this may come in useful for anyone using the Pi as a router but doesn’t want people using all the bandwidth.
I will be going through the iptables and tc configuration in this post, but I won’t go through the hostapd setup as that was the same as part 3 of my Raspi WiFi Access point guide.
I started off with a blank slate of Raspbian Server Edition again, and I didn’t need to install any utilities as iptables and tc are installed by default.
**Note** All command are run as root. If you are not running as root, prepend sudo to all commands
Setting up tc
tc is the program that is in charge of setting up the shaping rules.
Firstly, we will setup the default rule for the interface, which is wlan0 in this instance.
These 2 commands sets the default policy on wlan0 to shape everyone’s download speed to 64 kilobytes a second.
tc qdisc add dev wlan0 root handle 1:0 htb default 10
tc class add dev wlan0 parent 1:0 classid 1:10 htb rate 64kbps ceil 64kbps prio 0
Next, we’ll setup another class to shape certain addresses to a higher speed.
We also need to setup a filter so that any packets marked as such go through this rule
tc class add dev wlan0 parent 1:1 classid 1:5 htb rate 256kbps ceil 256kbps prio 1
tc filter add dev wlan0 parent 1:0 prio 1 handle 5 fw flowid 1:5
Once that class is setup, we’ll need to setup iptables to mark the specific packets we want to shape as such.
Setting up iptables
Firstly, we’ll create the mangle table that we need. I’ve used a custom chain in the mangle table in this snippet
The below code creates the new chains of shaper-in and shaper-out, and then sets up some rules for any packets coming in and out of wlan0 and eth0 to go through the new chains.
iptables -t mangle -N shaper-out
iptables -t mangle -N shaper-in
iptables -t mangle -I POSTROUTING -o wlan0 -j shaper-in
iptables -t mangle -I PREROUTING -i wlan0 -j shaper-out
iptables -t mangle -I PREROUTING -i eth0 -j shaper-in
iptables -t mangle -I POSTROUTING -o eth0 -j shaper-out
Once that is done, we can then setup the packet marking so that any packets from the 10.0.0.0/24 subnet gets marked with a 1, otherwise if the IP address is 10.0.0.5, they will get marked with a 5
iptables -t mangle -A shaper-out -s 10.0.0.0/24 -j MARK --set-mark 1
iptables -t mangle -A shaper-in -d 10.0.0.0/24 -j MARK --set-mark 1
iptables -t mangle -A shaper-out -s 10.0.0.5 -j MARK --set-mark 5
iptables -t mangle -A shaper-in -d 10.0.0.5 -j MARK --set-mark 5
With that done, any connections going through wlan0 should now be shaped to 64kbps unless you have the IP address of 10.0.0.5 in which case you will be shaped to 256kbps
If more shaping speeds or IP addresses are required, then step 2 in the respective sections will need to be modified / added onto to give you the extra options.
I used Speedtest Mini hosted on my own webserver to test the speeds while I was shaping the connections as it provided an easy to use interface, but wget on a big file can also be used to test the speeds.
Setting up router to auto-start
If you want the shaping to start automatically, put all the commands into 1 or 2 shell script files in /etc/network/if-up.d and they will be run automatically.
e.g. /etc/network/if-up.d/router and /etc/network/if-up.d/shaper
make sure they have both been chmodded to be executable by running this on both files
chmod +x /etc/network/if-up.d/router