Script: How to get a MAC address and device presence list of authorized WiFi clients across all APs

UPDATE2: Release v2.0.0 can combine WiFi+BT presence detection per device to get a more reliable result, especially using IPhones. BT detection is optional, if you'd like to use it, you'll need to buy e.g. a "Plugable BT4.0 USB Adapter" and plug it in to e. g. the TP-Link Archer C7v2 USB port. //

UPDATE: First draft has arrived on GitHub -


I've written a bash script that can monitor multiple OpenWrt Access Points from one master access point and detect STA clients connecting and disconnecting to provide a "cumulated" PRESENT or AWAY state per client across the whole network.

E.g. if device A is connected to AP A and disconnected from AP B it's "globally" marked online by the script in the "/tmp/active_clients" file. If it holds two connections (2.4 GHz and 5 GHz) and one of them disconnects and the other stays it's persisted in online state without going to trigger "->presentaway->present".

My aim is to provide clear logs on a "per device" basis to see when devices joins a WiFi network SSID and when they leave - no matter which of the many access points providing the SSID or band a device chose to connect to. It should be a general overview like this:

  • device A connected to SSID 1 at WifiAP1 -> device A is present
  • device A disconnected from SSID1 at WifiAP1 -> device A still present
  • device A connected (short after) to SSID 1 at WifiAP2 -> device A still present
  • device A disconnected from SSID 1 at WifiAP2.
  • It never came back on another AP for 5 minutes -> device A reported away with leave at WifiAP2.

I'm currently working on it; if you're interested, I could upload the script to GitHub.

I'd like to use the thread to share my knowledge. This could be extremely useful in case you have multiple access points and want easy-to-read logs or presence detection.

The first thing I've found is you have to take care when listing associated STA clients via CLI to filter the multiline output for "authorized: yes" clients. Someone could else enter a wrong password and get onto the online list "maliciously" as associated does not mean authorized.

Here's how I did grab the autorized WiFi clients via CLI on a single AP:

dumpLocalAssociatedStations ()
	# Usage:				dumpLocalAssociatedStations
	# Returns:				iw dev <all wlan devices> station dump
	#						cumulated result.
	# Example Result:		"aa:bb:cc:dd:ee:ff|" (without newline at the end)
	# Called By:			MAIN
	# Get all wlan interfaces with sub-SSIDs:
	# e.g. wlan0, wlan0-1, wlan0-2, wlan1, wlan1-1, wlan1-2, ...
	iw dev | grep -F "wlan" | cut -d " " -f 2 | while read file;
		# "file" contains one SSID Wifi Interface, e.g. "wlan0-1"
		# Get associated stations of current wlanX interface.
		# 	echo -n "$(iw dev "${file}" station dump 2> /dev/null | grep -Fi "on wlan" | cut -d " " -f 2 | sed "s/^/${file},/" | tr '\n' '|')"
		# Get authorized stations of current wlanX interface.
		echo -n "$(iw dev "${file}" station dump 2> /dev/null | grep "\(on wlan\|authorized:*.\)" | grep -B 1 "^.*authorized:.*yes$" | grep -v "^.*authorized:.*$" | cut -d " " -f 2 | sed "s/^/${file},/" | tr '\n' '|')"
	# Content already returned because iw dev was called loudly.

# Test with:
echo ";$(dumpLocalAssociatedStations)"

It outputs an easy-to-parse one-liner:


I'm now going to solve the event tracking across all access points with "syslog-ng" + "logread". Two milestones:

  • Track connection events AP-STA-CONNECTED and AP-STA-DISCONNECTED in real-time across all APs
  • Let "slave APs" (= APs not running the presence detector script) emit log lines in the above mentioned form ";....|" every 5 minutes to be able to "resync" in case of missed syslog events (due to reboot, sudden crash or disconnection of the slave APs from the master)

Let me know if you have cool ideas for my dev task :-).

Kind regards

How do you detect that? Do you ping connected devices every 10 minutes?

Probably this thread is helpful...

most clients will do a dhcp-request when connecting but a dhcp-ack when roaming, so grepping the dhcp-log for requests will give a good aproximation of what you want.

When logread emits a AP-STA-CONNECTED I'll put a line into the /tmp/associations.dto file, backing it up to ....dto.old before writing:


=0 means: PRESENT

After every connect event I'll go through that file and compare with the previous version. If a device counter (the zero) changed, I'll emit an "AWAY > PRESENT" event to a FIFO (which other scripts can consume easily).

After every disconnect event I'll go through the associations.dto file and mark the corresponding line of with the clients AP/band/MAC "=1".

Every minute, a scheduled function executes, looks at the .dto file and increases the counter if ">=1" with "+1" until it is "MAX_COUNTER". If the increase gets to MAX_COUNTER, it is not increased anymore but an "PRESENT > AWAY" event is emitted to my FIFO (for other scripts).

If I "miss" some AP-STA (logread) event from any AP station's syslog, I'll have to wait max. 5 minutes until the station emits a full associated and authenticated MAC list of its clients to its syslog and the master script can "sync" with the .dto contents and see if they are all current. If not, it will put "=0" or "=1" to correct an outdated state automatically. By this PASSIVE way to detect presence, my AP does not need to have an IP address in the WiFi networks it monitors, just a management network IP address is required over which it listens to other APs syslog 1) connect 2) disconnect 3) sync events.

1 Like

A few thoughts on this:

  1. Wi-Fi interfaces can be given a pre-determined definite name (instead of automatically generated like wlan0-1) through an option ifname in /etc/config/wireless. This may reduce the need to probe and enumerate your interfaces.

  2. OpenWrt has the iwinfo command as middle-ware to collect and parse some things about wireless status.

  3. The full version of wpad supports RADIUS accounting on any AP, including those with open or PSK authentication. RADIUS packets are generated whenever a station connects or leaves / is dropped. Even if you don't have a RADIUS server, RADIUS related messages are logged to syslog. These may offer more information. Also by setting an interim time, the RADIUS accounting will periodically confirm that a station is still connected.

1 Like

Cool, thanks for the input. Will upload the first "alpha" soon to show what I got working. Until now, script does fine as I put it to production.

I've updated the first post with a link where I've posted the fully functional script. It's already performing well in production. Will put up more documentation soon.

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