Wednesday, April 17, 2013

Automated guest Wifi password (Linksys Smart Wifi)

Here's my requirement: I want to automatically change the password on my guest wireless network, so that if I hand it out to guests, they can't pass it on to others or use it indefinitely.  That's all :)

I have 3 Wifi routers around the house.  Obviously I don't want to log in to all three each day and change the passwords.  With the risk of making mistakes.  So I want my linux server to take care of this feat.

I had implemented this once already with these three devices, but I recently upgraded their firmware and the mechanism broke completely.  The Wifi routers are Linksys 4200's which I upgraded to firmware 2.1.39.something.  This is called Linksys Smart Wifi firmware.  To make things even worse, I have them configured in bridge mode, so most functionality is not available.  There isn't even a UI to change guest network parameters manually even if I wanted to!
I knew guest network is still available because the SSID is broadcast, and I can see it on my laptop.

So I logged on to the router, and used the magic touch: F12 key opens developer tools in Google Chrome (I think it does now in IE as well).

I noticed several HTTP POST messages to the device like this:

Request URL:
Request Method: POST


Accept:*/* Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3 
Authorization:Basic YWRtayouwishTAwN3M= 
Content-Type:application/json; charset=UTF-8 
Referer: User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31 
X-JNAP-Authorization:Basic YWRtayouwishTAwN3M=



Interesting no? I left out the response, but there was a truck load of useful information.  The response was organized per action.  So for each 'action' in the payload, a response section is returned in JSON.
The routers apparently use some kind of REST-like protocol called JNAP.  Never heard of it.  But there's on of interest:


So I used curl on a linux box to send this separate request:

curl -H "X-JNAP-Action:" -H "X-JNAP-Authorization:Basic YWRtayouwishTAwN3M=" -d $POST_DATA -u $USER

And this returns:

  "result": "OK",
  "responses": [
  "result": "OK",
  "output": {
    "isGuestNetworkEnabled": true,
    "broadcastGuestSSID": true,
    "guestSSID": "ducnet-guest",
    "guestPassword": "guestpwd",
    "maxSimultaneousGuests": 5,
    "canEnableGuestNetwork": true,
    "guestPasswordRestrictions": {
      "minLength": 4,
      "maxLength": 32,
      "allowedCharacters": [
        "lowCodepoint": 48,
        "highCodepoint": 57
        "lowCodepoint": 65,
        "highCodepoint": 90
        "lowCodepoint": 97,
        "highCodepoint": 122
    "maxSimultaneousGuestsLimit": 50

So with some trial and error, I figured out that I can send following payload as a POST request to the router and the password would be set:

Pay attention to these things when sending the request:

  • Remove spaces from the JSON in the payload.  The response appears as if it worked, but it doesn't.
  • Set the 2 JNAP headers (X-JNAP-Action and X-JNAP-Authorization)
  • Provide the username and password for the HTTP authentication (-u param with curl)

The response looks like this:

  "result": "OK",
  "responses": [{
    "result": "OK"

And that's it.  Poor all this in some additional scripts and add cron to launch it whenever you like (e.g. use current month and year as password).  Works for me!