jake kara, software engineer ‣ A library for picking your Linksys router's brain ░

A library for picking your Linksys router's brain

Your Linksys Smart Wi-Fi will tell anyone who asks whether the default password has been changed. Yeah.

I wrote a quick library for getting info and controlling Linksys Smart Wi-Fi routers.

Here’s the repo.

jnap - library for talking to Linksys router API

This library allows you to programatically talk to Linksys Smart Wi-Fi routers that use HNAP (or JNAP, I’m not really sure what it’s called).

Install from this repo

Run this at the command line:

pip install git+git://github.com/jakekara/jnap.git 

Run the demo script

  1. Download the script jnap-demo.py in the demo folder of this repo

  2. Assuming your router is at

    python demo/jnap-demo.py 2> /dev/null

Enter your password when prompted. You can enter an invalid password, and the router will just complain on all the actions that require authorization.

The reason I redirected stderr to /dev/null is it will warn that SSL verification is off constantly. SSL verification fails because the router’s cert is not trusted. You could forego the stderr redirect if you want to see the warnings. You could also use http:// in front of your router’s IP address.

Using in your code

The demo script is well documented and uses all of the features I bothered to implement. It serves as a better tutorial than I have the time to write right now. Nonetheless, here is a quick synopsis of some key features

  # import the library
  from jnap.router import Linksys

  # set up a router connection with an optional admin password
  router = Linksys(IP_ADDRESS, pw="PASSWORD")

  # now you can just call actions that I've implemented, like...
  # check if the router has a default password

  # test a password string against the admin password to see if they
  #  match

API method documentation

All of the methods jnap/router.py are well documented in the comments. Here is the documentation as it appears in the comments. These can all be called on the router instance.

    password - set the password to use for authentication
        args -    pw - password string
               uname - defaults to admin. I don't think anything
                       else will work
        rets - none

    check_password - Check whether a supplied string is the admin password
                     of the router. Yes, that's a thing.
              args -     pw - the password to test
                     [user] - the username (defaults to "admin"). this is
                              optional and I'm not sure if any other user name
                              would actually work here, although technically
                              these routers support more than one user.
              rets - same as do_action

 has_default_password - Check whether the router still has its default password.
                        Yes, that's a thing. I believe these routers are not
                        hardcoded, they come with per-unit passwords printed on
                        a sticker.
                 args - none
                 rets - same as do_action

 get_users - list all the router's users. Generally just "admin" and "guest"
      args - none
      rets - same as do_action

 get_device_info - get a bunch of summary info about the device
            args - none
            rets - same as do_action

 stop_ping - stop pinging
      args - none
      rets - same as do_action
     notes - authentiation required

 start_ping - start pinging something
       args -      host - host to ping
              byte_size - optional int between 32 and 65500 to specify
                          ping payload size
                  count - number of pings to send. (None for indefinite!)
       rets - same as do_action
      notes - authentication required

 get_ping_status - check on how a ping action is going
            args - none
            rets - same as do_action
           notes - authentication required

 start_traceroute - start tracerouteing to some host
             args - host - a hostname or IPv4 addr string
             rets - same as do_action
            notes - authentication required

 stop_traceroute - stop a traceroute action
            args - none
            rets - same as do_action
           notes - authentication required

 get_traceroute_status - get the status of a traceroute action
                  args - none
                  rets - same as do-action
                 notes - authentication required


All of the above methods are implemented by calling the following helper method, so you can easily add support for JNAP API calls you want to make:

 do_action - Perform a specific API call. This is a helper function
             used to build the methods below.
      args - action - the action to perform
           - [headers] - any additional header values to send
           - [data]    - optional POST data. Weirdly doesn't work with a
                         dict, so "{}" has to be in quotes. I think that might
                         have to do with the requests library, but I haven't looked
                         under the hood at whether it's replacing {} with nothing.
                         That seems to be what's going on based on the HTTP traffic.
      rets - returns a response to the HTTP POST request (see requests library)
     notes - maybe I should make this return the JSON