Rate limited guest WLAN on OpenWrt
Published: 2015-02-01Updated: 2020-07-21
I have set up a basic guest access point with limited bandwidth. There's two parts to it: setting up the AP, then setting the limits. This is a quick walkthrough, based on the OpenWrt wiki, to which I have added the instructions for a multi-device setup (ie a network configuration with one router and one or more switches or access points).
Creating a guest access point (single router)
Add a guest interface to /etc/config/network
:
config interface 'guest'
option proto 'static'
option ipaddr '192.168.3.1'
option netmask '255.255.255.0'
And one to /etc/config/wireless
. Make sure to get
the device name right, it may differ between platforms.
config wifi-iface
option device 'radio0'
option network 'guest'
option mode 'ap'
option ssid 'OpenWrt Guest Network'
option encryption 'psk2+ccmp'
option key 'just don't make it too easy?'
Add an entry for the DHCP server to /etc/config/dhcp
.
Since this is a guest WLAN, you can set a relatively low lease
time:
config dhcp 'guest'
option interface 'guest'
option start '2'
option limit '10'
option leasetime '2h'
option ignore '0'
To determine the start number, take into account the number of network devices (routers, switches, access points) requiring a static IP so the DHCP range does not conflict with any static IPs. E.g. for a router + AP setup, you'd want to set your start value to '3'.
Lastly, we implement some extra firewall rules in
/etc/config/firewall
. First, we block all incoming
or forwarding traffic. Only outgoing traffic is allowed.
config zone
option name 'guest'
option list 'guest'
option input REJECT
option output ACCEPT
option forward REJECT
Next we give the guest AP a direct line to the WAN, and isolate it from the regular LAN:
config forwarding
option src 'guest'
option dest 'wan'
DNS rules:
config rule
option src 'guest'
option dest_port '53'
option proto 'tcpudp'
option target ACCEPT
DHCP rules:
config rule
option src 'guest'
option src_port '67-68'
option dest_port '67-68'
option proto 'udp'
option target ACCEPT
Restart the network and firewall (or, if you wish, reboot your router). Now you have a fully functional isolated guest AP.
Guest AP (two or more network devices)
If you are not familar with how VLANs work in OpenWrt, read my VLANs primer before proceeding. Here, I assume you only have one VLAN by default (VLAN ID 1). Check the present VLANs so you don't accidentally overwrite any existing ones. I will be providing the code that goes into the configuration files themselves, but the web interface is better for a comprehensive overview once you need to deal with multiple VLANs.
First, you need to configure a new VLAN on the router and all
switches or access points. Unless stated otherwise, all code
goes in /etc/config/network
). A few rules of thumb:
- Make sure the VLAN ID is the same across all devices.
- On each network device, only the port(s) connecting the backbone of the network should be part of the VLAN.
- Ports that are part of multiple VLANs should be tagged in every VLAN (I cannot stress this enough!).
- Every VLAN should also include the CPU (tagged by default).
Schematically, in a router - access point combination, there's only one port on each device connecting to another network device. As such, the VLAN will only contain that port (here port 3) and the CPU, both tagged (indicated by the t behind the number), so in this case, our VLAN config will look like this:
config switch_vlan
option device 'rtl8366s'
option vlan '2'
option ports '3t 5t'
Likewise, in a setup with (in that order) a router, a switch, and an AP, the router would have one port in the VLAN, the switch two, and the AP one, and so on.
Again, a warning: make sure every port part of more than one VLAN is tagged in every single VLAN it is part of. Failure to do so may render your device inoperable.
The interface stanza should look as follows. Note that we specify an interface, unlike in a single router setup.
config interface 'guest'
option ifname 'eth0.2'
option proto 'static'
option ipaddr '192.168.3.1'
option netmask '255.255.255.0'
On each access point, we replicate the same stanza, but with two substantial differences:
- We add an interface type, namely bridge (this will put the LAN and WLAN interfaces on the AP in one network).
- We set a different static IP (typically incremented by one).
Your config should look like this:
config interface 'guest'
option ifname 'eth0.2'
option type 'bridge'
option proto 'static'
option ipaddr '192.168.3.2'
option netmask '255.255.255.0'
Replicate the wifi interface config on each access point (see above for the sample code). Disable the wireless on all other network devices.
These are the only changes you need to apply for a multi-device setup. The DHCP server only runs on the main router, so you do not need to edit any related settings on any switches or access points; do make sure though that the static IPs do not conflict with the DHCP range you set. As for the firewall, you should replicate all stanzas provided above on every network device.
A note on swconfig versus DSA
Up till 19.07, OpenWrt has relied on swconfig to configure internal switches. Upstream Linux, however, has been progressively implementing DSA (Distributed Switch Architecture) to handle Ethernet switches. In its effort to stay close to upstream and lighten the maintenance burden, OpenWrt plans to migrate to DSA as well. At this point (July 2020), MT7621 is one of the few OpenWrt targets in OpenWrt master with DSA support. For end users, this means a few practical things:
- swconfig is phased out on targets which switched to DSA.
- No more eth0/eth1/eth1.1/... interface names; ports are exposed
individually and bridged, e.g. a four-port switch will now have
option ifname 'lan1 lan2 lan3 lan4'
instead ofoption ifname 'eth0.2'
. - A tagged interface now looks like
lan1.100
for a VLAN ID 100 e.g.
LuCI support for DSA is in the works, but at this stage DSA configuration is fully handled through the command line.
Limiting the guest AP's bandwidth
From Barrier Breaker (14.07) on, it is recommended to use
<abbr title="Smart Queue Management">sqm</acronym>-scripts
,
which has also an easy LuCI frontend if you wish. Set the network
device to the interface you want to control (in this case,
wlan0-1
). My /etc/config/sqm
looks
like this:
config queue 'eth1'
option qdisc 'fq_codel'
option script 'simple.qos'
option qdisc_advanced '0'
option linklayer 'none'
option enabled '1'
option interface 'wlan0-1'
option download '8000'
option upload '2000'
More info on SQM can be found here.
The instructions below for tc
are kept for historical reference
and are now deprecated, in favour of SQM.
Tc is a bit hackish, but it works. There's also wshaper
,
which depends on tc
and looks a bit more user-friendly.
Install tc:
# opkg install kmod-sched kmod-sched-core tc
After all the packages are installed, add the following to
/etc/rc.local
:
# Load the necessary modules
lsmod | grep sch_htb &> /dev/null || insmod /lib/modules/$(uname -r)/sch_htb.ko
# Traffic control for the guest network.
# First we flush the rules to make sure no cruft is left;
# Then we limit traffic to 200 KBps (despite the notation
# tc means KBps) with a 250 KBps ceiling.
/usr/sbin/tc qdisc del dev wlan0-1 root
/usr/sbin/tc qdisc add dev wlan0-1 root handle 1:0 htb default 10
/usr/sbin/tc class add dev wlan0-1 parent 1:0 classid 1:10 htb rate 200kbps ceil 250kbps prio 0
/usr/sbin/tc filter add dev wlan0-1 parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
# For reference: the command to check the limits imposed
# tc -s -d class show dev wlan0-1