Wi-Fi: Hostapd VLAN for guest network

Hello all and sorry for my lack of posts this year.

I have had many visitors who have given my private Wi-FI password because they needed internet access, but later I thought that I don’t like having them on my private network.

What I wanted was locking them out, without creating a new “Guest Network”, but keeping the same SSID/key. In other words, I’d wanted my trusted devices and the visitor’s devices on two Layer 2 separated networks. The answer is: VLAN.

Oh… The trusted list is a MAC address list.

My access point is based on hostapd, a linux daemon that is managing the Wi-Fi cards (PCI or USB) and it has a couple of settings to manage VLANs:

# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
# 0 = disabled (default)
# 1 = option; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0

# Station MAC address -based authentication
# 0 = accept unless in deny list
# 1 = deny unless in accept list
# 2 = use external RADIUS server (accept/deny lists are searched first)
#macaddr_acl=0

# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
# and br%s.%d if a tagged interface is given, provided %s = tagged interface
# and %d = VLAN ID.
#vlan_bridge=brvlan

As you can see, one option is using the ‘accept_mac_file’ file, which permits a static mapping of your MAC Addresses <-> VLANs. Anyway, using this approach would force you to list all the MAC addresses of every device connecting to your Wi-Fi network. That’s because you can’t use any wildcard for the MAC addresses on that file!

But there is another approach, using RADIUS.

With ‘dynamic_vlan=1’ plus ‘macaddr_acl=2’, the accept/reject request based on the MAC Address pass through the RADIUS server, which reply with or without the “Tunnel-Private-Group-ID” (VLAN ID). The RADIUS server must be configured to accept any request (remember, the network is already protected by your PSK key) but including the “Tunnel-Private-Group-ID” parameter only to the unknown MAC addresses, because we want the well known MACs to be left on the default VLAN (dynamic_vlan=1 # use default interface if RADIUS server does not include VLAN ID).

This is the theory. Now the practice..

apt-get install freeradius

On a Ubuntu 15.10 I didn’t modify much of the freeradius configuration.

The most important file is /etc/freeradius/users in which we can define the replies to give back to hostapd daemon. You must configure first the well known MAC addresses with the Auth-Type ‘Accept’ but without the VLAN specification. For example my ESP8266 has the ’18:fe:34:fa:5a:ba’ MAC address, so…

18fe34fa5aba Auth-Type := Accept

Then, if an unknown MAC address is requesting connectivity to our network, we have a default entry accepting it and assigning the guest VLAN ID to it. On the hostapd side, this means that the device will be attached to the brvlan1000 bridge.

DEFAULT Auth-Type := Accept
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id := 1000

To complete the post, here’s my hostapd.conf:

interface=wlan1
bridge=br0

# AP Name Definition
ssid=MyNetwork
hw_mode=g
ieee80211n=1
ieee80211d=1
country_code=GD
wmm_enabled=1
channel=1

# WPA-PSK Passphrase definition
wpa=2 # WPA2 only
auth_algs=1 # 1=wpa, 2=wep, 3=both
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_pairwise=TKIP
wpa_passphrase=secret

# RADIUS authentication server
own_ip_addr=127.0.0.1
auth_server_addr=127.0.0.1
auth_server_port=1812
auth_server_shared_secret=testing123

# VLAN Configuration #
#
# use default interface if RADIUS server does not include VLAN ID
dynamic_vlan=1
# defining vlan
vlan_file=/etc/hostapd/hostapd1.vlan
# use external RADIUS server for MAC Address filtering
macaddr_acl=2

Do not forget to define the VLANs on /etc/hostapd/hostapd1.vlan (1000 + default) and attach the brvlan1000 to your firewall with your rules.