Here is a script I wrote that scrapes the web interface of a router running DD-WRT. The script looks for the MAC addresses of wireless users. When it sees a MAC address that it hasn’t logged before it issues an alert. To help identify the new equipment, a portion of the MAC address is sent to an IEEE OUI database search (Internet connection required) to determine the manufacturer name. This script is intended to be ran periodically from crond on a system other than the router. When the script detects a new MAC address it writes to STDOUT, in most cron configurations this will result in an email being generated to the local system user running the process, or to another address specified in the MAILTO variable.
Sample /etc/crontab entry
* * * * * root /usr/local/sbin/wifi-macs.sh
Sample output generated when a new iPhone connects to the ‘MySSID’ network.
#Set the username used for web access to the router
ROUTER_USER="root"
#Set the password used for web access to the router
ROUTER_PWD="admin"
#Set the IP address where the router can be reached, optional port
#number can be specified like 192.168.1.1:80
ROUTER_IP="192.168.1.1"
#If you have your router setup to support https, change to https
PROTO="http"
LOGS="/var/log/wifi"
read_macs () {
while read line
do
if [ "${line//active_wireless/}" != "$line" ]; then
OFS="$IFS"
IFS="\'"
for word in ${line[@]}
do
if [ "${#word}" -eq "17" ]; then
mac="${word//:/}"
if [ "${#mac}" -eq "12" ]; then
echo "$mac"
fi
fi
done
OFS="$IFS"
mac=""
word=""
fi
done
}
read_ssid () {
while read line
do
if [ "${line//wl_ssid/}" != "$line" ]; then
line="${line##*"wl_ssid::"}"
line="${line%%"}"*}"
echo "$line"
fi
done
}
read_company () {
while read line
do
if [ "${line//"(base 16)"/}" != "$line" ]; then
line="${line##*'(base 16)'}"
line="${line:2}"
echo "$line"
fi
done
}
if ! [ -d "$LOGS" ]; then
echo "Logs directory $LOGS does not exist" >&2
exit 1
fi
wldata="`curl -s --user $ROUTER_USER:$ROUTER_PWD $PROTO://$ROUTER_IP/Status_Wireless.live.asp`"
ssid="`echo $wldata |read_ssid`"
macs=(`echo $wldata |read_macs`)
for mac in ${macs[@]}
do
if ! [ -f "$LOGS/$mac" ]; then
company="`curl -s "http://standards.ieee.org/cgi-bin/ouisearch?${mac:0:6}" |read_company`"
echo "Alert new client found on $ssid MAC: $mac ($company)"
echo "New MAC Address detected: `date`" >>$LOGS/$mac
echo -e "${mac:0:6}\t\t$company" >>$LOGS/$mac
echo -e "Additional Data:\n$wldata" >>$LOGS/$mac
fi
done
4 thoughts on “Detect Wi-Fi Clients on your DD-WRT Router”
jamen ·
I can’t find a problem with the code, but when i run it with ./sh wifi-macs.sh I get
wifi-macs.sh: 74: wifi-macs.sh: Syntax error: “(” unexpected (expecting “fi”)
Chris ·
Hi Jamen,
You are running the script with /bin/sh, if you didn’t include the shebang (#!/bin/bash) in the script it will be using /bin/sh as the interpreter. This script is meant to be run on a computer with persistent storage and not on the dd-wrt device itself. If you are running this on the device, the busybox shell probably doesn’t understand the bashisms I’ve used. It would be cool to run it all on the device, and probably wouldn’t even require a password or scraping the web interface, but I didn’t take that approach.
Hardy ·
Hi Chris,
Not sure if you’re still maintaining this but I thought I would try. The script works great, I’ve added an extra layer of IFTTT notification when the email is sent so I get updates if new connections are made. One thing I noticed is that in all of my notifications, the part after the MAC is blank like this:
Alert new client found on TRENDnet MAC: A020A60AC83D ()
Is there something I need to add to get the part inside the brackets? Also, are there other details that dd-wrt can pass along in the initial message – like the new IP address for example?
Thanks for the awesome script!
Kyle Silfer ·
I put this script to use and thanks very much for sharing, but I discovered that the output of Status_Wireless.live.asp doesn’t properly show users connecting to a virtual interface (such as a guest network). The SSID and Mac address of the virtual interface are not distinguished from the physical interface. I was interested in recording connections to the physical interface and not the virtual, but it’s impossible to tell which is which. 🙁