Custom application/script: Iterate through WiFi devices, compare, send information to server

  • ATTENTION! As of November 1, 2020, you are not able to reply to threads 6 months after the thread is opened if there are more than 500 posts in the thread.
    Threads will not be locked, so posts may still be edited by their authors.
    Just start a new thread on the topic to post if you get an error message when trying to reply to a thread.

birgersp

Occasional Visitor
Hello,

I am about to install Merlin on my Asus-AC86U router.

I want to create a lightweight application or script that has one job: notify my server whenever a WiFi device enters or leaves my network.

My inital idea is: Add a small script that runs on boot. The script loops endlessly (with 1 sec delay between each iteration). The script somehow retrieves a list of all WiFi devices currently connected to my network, compares with data from the previous iteration. If there is a difference in the datasets, it means devices have entered or left the WiFi network area. Then, send this information to my server (that part I can figure out on my own, I think).

So a couple of questions:

1) Can scripts that are executed on start run in a neverending loop, or will this not work? Will it block execution of other applications on my router?
2) How can I retrieve data (mac addresses) of each device currently connected to or in the area of my WiFi network? Preferably in a bash script, but I'm all ears for e.g. Python/native application solutions.
3) If the scripts cannot run in a neverending loop, how should I store the data about the connected devices between each execution of the script?
 

ColinTaylor

Part of the Furniture
There are already scripts posted in these forums that do this. Use the Better Search function to find them and modify them to your own needs. Here is an example.
 

birgersp

Occasional Visitor
Thanks! So I can add this script to `/jffs/scripts/services-start/somescript`? And will this not block?
 

ColinTaylor

Part of the Furniture
Thanks! So I can add this script to `/jffs/scripts/services-start/somescript`? And will this not block?
services-start is a script not a directory. So you would need something like this as the minimum contents of that script.
Code:
#!/bin/sh
/jffs/scripts/wireless_monitor.sh &
Note the ampersand to run it in the background.
 

birgersp

Occasional Visitor
Awesome! For anyone interested I will also add this script to kill the wireless_monitor.sh script if needed:

(EDIT: removed incorrect script)
 
Last edited:

ColinTaylor

Part of the Furniture
Awesome! For anyone interested I will also add this script to kill the wireless_monitor.sh script if needed:

Bash:
#!/bin/bash
ps -ef | grep '[w]ireless_monitor.sh' | awk '{print $2}' | xargs kill -9

That script is incompatible with the router's shell. You should use something like this:
Code:
#!/bin/sh
ps | grep '[w]ireless_monitor.sh' | awk '{print $1}' | xargs kill -9

P.S. Don't use /bin/bash. Even though some routers have a symlink for it the router's shell is not bash compatible.
 

birgersp

Occasional Visitor
Thanks! Now my next problem is; how can I send data from my router to my server?

I was thinking just to send a single UDP packet, but the examples I find online doesn't really work.

Code:
echo -n "hello world" | /dev/udp/serverip/15243
# /dev/udp/ doesnt exist

# or

echo -n "hello world" | nc -4u -w0 serverip 15243
# fails with 4 being an invalid option

# or

echo -n "hello world" | nc -u -c serverip 15243
# fails with u being an invalid option
 

ColinTaylor

Part of the Furniture
Cutting and pasting random examples from the internet usually doesn't work on the router because it's not a full blown Linux distribution.

What data is your server actually expecting to receive?
 

birgersp

Occasional Visitor
My idea is to send the MAC address of each device that is connected.

Code:
#!/bin/sh

msg=""
for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
do
    msg=$msg$(wl -i $iface assoclist | sed "s/assoclist/$iface/g")
done

echo "$msg" # <--- send this data
 

birgersp

Occasional Visitor
Cutting and pasting random examples from the internet usually doesn't work on the router because it's not a full blown Linux distribution.

What data is your server actually expecting to receive?

To answer your question: My server is expecting to receive a UDP packet with a small data amount. The server will parse the data and act accordingly (but this part I don't need help with). What I don't quite understand is how to send messages from my router to some host (preferably using UDP).
 

ColinTaylor

Part of the Furniture
Do you really need to add the interface name to output data or will just the MAC addresses be sufficient?

The router's built-in nc doesn't support UDP connections. Can you use TCP or does it have to be UDP?
 

birgersp

Occasional Visitor
Do you really need to add the interface name to output data or will just the MAC addresses be sufficient?

The router's built-in nc doesn't support UDP connections. Can you use TCP or does it have to be UDP?

MAC addresses would be sufficient. It can be TCP, but the reason I wanted UDP was that I feel it is less chance for the script to crash. In my head it sounds better that the router just sends this information regardless if someone will pick it up or not. The router shouldn't have to worry about handshaking etc. But yes it can be TCP if that is easier.
 

birgersp

Occasional Visitor
So I got this to work. Not UDP but I guess it will be fine.

Code:
#!/bin/sh

msg=""
for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
do
        msg=$msg$(wl -i $iface assoclist | sed "s/assoclist/$iface/g")
done
echo "$msg" | nc -w0 10.0.0.11 42069
 

ColinTaylor

Part of the Furniture
Can't post the text for some reason, so....

Untitled.png

N.B. there should be a space separator when concatenating the $msg strings.
 
Last edited:

birgersp

Occasional Visitor
Perfect! So here's the end result that is running on my router now:

Code:
#!/bin/sh

echo "Starting wireless device observer"
while sleep 2
do
        msg=""
        for iface in $(nvram get wl_ifnames) $(nvram get wl0_vifs) $(nvram get wl1_vifs)
        do
                msg="$msg $(wl -i $iface assoclist | awk '{print $2}')"
        done
        echo $msg | nc -w0 10.0.0.11 42069 2>/dev/null
done

Tested it on the receiving end aswell, works like a charm.

I'm so grateful for your help. Thank you friend!
 

dosborne

Very Senior Member
Although you got it working, another approach, and a style I personally prefer, would be to have your router simply collect and store the data and let your server get it when necessary.

I use this approach for a number of reasons, but mainly to have the source device do as little "work" as possible (and potentially removing the need for a USB drive, entware, etc).

For example in your case, you could have a simpler script that stored all active connection information in a text file. By placing this file in a shared location the server in your case could read it and do all the necessary processing, storage, logs, etc.

Not in any way suggesting your approach is bad, just giving you more ideas to consider.

Thanks for sharing how you got it working. It is always great to see the tweaks and mods people make and I'm sure this will be useful for someone else too.
 

birgersp

Occasional Visitor
Although you got it working, another approach, and a style I personally prefer, would be to have your router simply collect and store the data and let your server get it when necessary.

I use this approach for a number of reasons, but mainly to have the source device do as little "work" as possible (and potentially removing the need for a USB drive, entware, etc).

For example in your case, you could have a simpler script that stored all active connection information in a text file. By placing this file in a shared location the server in your case could read it and do all the necessary processing, storage, logs, etc.

Not in any way suggesting your approach is bad, just giving you more ideas to consider.

Thanks for sharing how you got it working. It is always great to see the tweaks and mods people make and I'm sure this will be useful for someone else too.

Appreciate the feedback! And yes I agree, it would be better if the router didn't have to worry about conveying the information. It should just store it so other applications can read it.

But, I want the "detection" of a new device to be fast, so the script that stores the information should be run at least once every 2 seconds. And I do feel like that would create an unnecessary amount of writing to and reading from the router's drive. But maybe that is irrational? I just don't want to burn out my routers SSD or whatever with my scripts.

Also, how would you configure the data to become available?

I changed my script to use UDP instead of TCP, and been testing it a lot today. For whatever reason, after about 70 minutes then my server no longer gets UDP packages from the router, even though the script (neverending loop) is still presumably running (the process is alive). I am not 100% sure if this is because of my server or the router, but I suspect the router because I have other, similar applications running on my server and this is the first time I have encountered this error...

So I am wonder if perhaps there is a better way to schedule the script to run every 2 seconds, rather than putting it in a neverending loop with a sleep. With cru I can run it at no shorter than 1 minute intervals.
 

dosborne

Very Senior Member
Also, how would you configure the data to become available
Save it to a location that is accessible vis samba, or ftp,...
 

birgersp

Occasional Visitor
Thanks!

So it turns out that my phone connects to my WiFi network just a little too slow for this system to work as intended.

Now I am wondering: is it possible for my router to detect that my phone is in WiFi range, even when the phone hasn't (yet) connected to my WiFi network?
 
Last edited:

Similar threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top