Seven years ago, I hacked together some code to update my Ecobee WiFi thermostat temperature depending on whether I was home. While my newer Ecobee thermostat has room occupancy sensors that make this tracking automatic, back then I had to poll my WiFi access point through SNMP to look for my phone’s MAC address in its table of associated clients.

Recently I needed to do something similar to pass to my Z-Wave controller but it seems that Apple has removed SNMP support from its Airport Extreme firmware some time ago.

Since the macOS Airport Utility is able to show the list of connected clients on each AP, I figured there must be a way to easily get that same information through something other than SNMP.

Some searching landed me at AirPyrt-Tools, which is a tool that can communicate with AirPorts over their older ACP protocol. While I didn’t find a way to get the client node status directly through ACP, I did discover that it’s possible to enable SSH with the tool:

$ python -m acp -t 192.168.1.15 -p (password) --setprop dbug 0x3000 INFO:connecting to host 192.168.1.15:5009 [...] $ python -m acp -t 192.168.1.15 -p (password) --reboot

Enabling SSH reveals an OpenSSH daemon on port 22 which can be logged into as root with the AP’s admin password. To my delight, I learned that the Airport Extreme runs NetBSD (full dmesg):

Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 The NetBSD Foundation, Inc. All rights reserved. Copyright (c) 1982, 1986, 1989, 1991, 1993 The Regents of the University of California. All rights reserved. NetBSD 6.0 (build.kernel-target.conf) #0: Thu Nov 2 10:49:34 PDT 2017 root@xapp29.apple.com:/BuildRoot/Library/Caches/com.apple.xbs/Sources/J28E/AirPortFW-77900.2/Embedded/Firmware/NetBSD/Targets/J28E/release/obj/build.kernel-target.conf total memory = 256 MB avail memory = 229 MB timecounter: Timecounters tick every 10.000 msec mainbus0 (root) cpu0 at mainbus0 core 0: 1 GHz Cortex-A9 r4p0 (Cortex core)

Accessing the list of associated clients can be done with ifconfig wlanN list sta on each of the 4 wlan interfaces.

# ifconfig wlan0 list sta ADDR AID CHAN TXRATE RXRATE RSSI IDLE TXSEQ RXSEQ CAPS FLAG 08:66:98:xx:xx:xx 7 149 526M 24M -66.0 9 0 0 EP AQEP RSN HTCAP WME (rssi -73:-66:-74 nf -92:-92:-92) dc:a4:ca:xx:xx:xx 6 149 877M 877M -55.0 4 0 0 EP AQEH RSN HTCAP WME (rssi -58:-55:-56 nf -92:-92:-92)

To gather a single list of all associated client MAC addresses on a group of AirPort APs, a Ruby script with net/ssh can make it easy: