Wednesday, July 20, 2016

Script to toggle LEDs on the Netgear Nighthawk AC1900 / R7000

I recently purchased the Netgear Nighthawk AC1900 dual-band router, to go along with my new faster Internet connection.

First off, I'll say- I wasn't a fan of Netgear's past home routers, but this one is quite amazing!  Not only can it keep up with my 1Gbps fiber connection, it also seems to have massively improved the wireless situation in my home over my previous Linksys router.

Anyway, enough of that.  One funny thing about this router, in addition to looking like a 1990s stealth aircraft, is that it's covered with SUPER HIGH INTENSITY WHITE LEDs.  They add to the sleek look, for sure, but you can practically read by them in a dark room.  (!)  Not so great if you happen to sleep in the same room with the router.

Thankfully, the Advanced Setup UI provides a mode to turn off all the LEDs (save for the power LED, which I just stuck a piece of gaffers tape over.)

I like the status LEDs, though, so I thought - wouldn't it be nice to be able to programatically toggle them?

I was hoping I could do it with a simple request from curl, but it turns out you need to auth to the setup page and retrieve a timestamped id token, probably as an anti-CSRF measure (albeit not a bulletproof one.)  So, voila - a quick & dirty python script to toggle the LEDs on the nighthawk router.

Requirements:
Python 2.7
Python requests library

Download link: http://cdn.phreakmonkey.com/r7000-LEDs.py

Script:


#!/usr/bin/python2.7
# Quick and dirty script to toggle the super-bright LEDs on the Netgear
# Nighthawk R7000 router.  Tested on FW V1.0.5.70_1.1.91.  YMMV.

import requests
import sys

# !!!
# IMPORTANT:  Put your actual router password and router IP address below:
# !!!
ROUTERADMIN = 'admin'
ROUTERPASS = 'password'
ROUTERADDR = 'http://192.168.1.1/'

# First, we have to get a valid timestamp from the settings page:
r = requests.get(ROUTERADDR + 'start.htm',
                 auth=(ROUTERADMIN, ROUTERPASS))
r = requests.get(ROUTERADDR + 'LED_settings.htm',
                 auth=(ROUTERADMIN, ROUTERPASS))
o = r.text.find('led_settings.cgi?id=')
if o == -1:
  if r.text.find('multiLogin') > -1:
    print 'Error: Another browser is currently logged into the router.'
  else:  
    print 'Invalid response from router:'
    print r.text
  sys.exit(1)

o2 = r.text[o:].find('"')

# Next, construct the CGI URL with the returned timestamp
led_url = ROUTERADDR + r.text[o:o+o2]

if len(sys.argv) == 2 and sys.argv[1].upper() == 'OFF':
  data = 'Apply=Apply&led_settings=turn_off&led_now=en_blink'
else:
  data = 'Apply=Apply&led_settings=en_blink&led_now=turn_off'

# Send the magic command:
r = requests.post(led_url, data=data, auth=(ROUTERADMIN, ROUTERPASS))
print 'Status code: %d' % r.status_code
#print r.text

# Avoid "multiLogin" errors:
r = requests.get(ROUTERADDR + 'LGO_logout.htm', auth=(ROUTERADMIN, ROUTERPASS))