Categories
Uncategorized

Using Python Scripts to Control WiFi Router

Controlling network access of a specific device to a router using web interface is a pain. Thanks to Mathieu Velten, who developed pynetgear, a Python package that supports scripting Netgear router, by reverse engineering the Netgear Genie App.

I wrote the following code utilizing the pynetgear package to turn on (Allow) and off (Block) network access for a specific device to my router.

#!/usr/bin/env python
import sys
import time
import click
from pynetgear import Netgear


class NetgearManager:
    """
    Netgear Router Manager
    """
    def __init__(self, pwd):
        self.session = Netgear(password=pwd)

    def search_connected_device_by_name(self, name):
        found = []
        for device in self.session.get_attached_devices():
            if device.name == name:
                found.append(device)
        if len(found) >= 0:
            return found
        return None

    def get_device_status_by_name(self, name):
        devices = self.search_connected_device_by_name(name)
        if len(devices) > 1:
            print(f'More than one device has the name {name}', file=sys.stderr)
            for d in devices:
                print(d.ip, d.type, d.mac, d.allow_block_device)
        return False

    def set_device_status_by_name(self, name, status_code, delay):
        assert status_code in ['Allow', 'Block']
        devices = self.search_connected_device_by_name(name)
        if len(devices)==1:
            mac_address = devices[0].mac
            return self.set_device_status_by_mac(self, mac_address, status_code, delay)
        elif len(devices)>1:
            print(f'More than one device has the name {name}', file=sys.stderr)
            for d in devices:
                print(d.ip, d.type, d.mac, d.allow_or_block, file=sys.stderr)
        return False

    def set_device_status_by_mac(self, mac, status_code, delay):
        if delay > 0:
            time.sleep(delay)
        return self.session.allow_block_device(mac, device_status=status_code)

@click.group()
def cli():
    pass

@click.command()
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=False, help='Netgear outer admmin password')
@click.option('--name', help='Device name')
@click.option('--mac', default=None, help='Device MAC address')
@click.option('--status', help='Status: Allow or Block')
@click.option('--delay', default=0, help='Time delay in minutes')
def switch(password, name, mac, status, delay):
    manager = NetgearManager(password)
    delay *= 60                 # minutes to seconds
    if mac:
        result = manager.set_device_status_by_mac(mac, status, delay)
    else:
        result = manager.set_device_status_by_name(name, status, delay)
    if not result:
        msg = f'Cannot switch device {name} status to {status}'
        print(msg, file=sys.stderr)

@click.command()
@click.option('--password', prompt=True, hide_input=True, confirmation_prompt=False, help='Netgear outer admmin password')
def show(password):
    manager = NetgearManager(password)
    devices = []
    for idx, dev in enumerate(manager.session.get_attached_devices()):
        print(str(idx), dev.name, dev.ip, dev.type, dev.mac, dev.allow_or_block)

cli.add_command(switch)
cli.add_command(show)

if __name__ == '__main__':
    cli()


Leave a Reply

Your email address will not be published.