"""Consultas seguras al ASUS RT-AX88U PRO desde la Raspberry.""" import html import re import shlex import subprocess import sys ROUTER = "jjminguez@192.168.50.1" KEY = "/home/pi/.ssh/router_control" SSH_BASE = [ "ssh", "-i", KEY, "-o", "BatchMode=yes", "-o", "ConnectTimeout=8", ROUTER, ] # Reservas que ya existian antes de reconstruir la lista desde los leases. LEGACY_RESERVATIONS = { "82:CC:3C:7D:0F:41": "192.168.50.194", "72:2A:0C:FE:5F:04": "192.168.50.158", "E0:1F:FC:A9:DC:73": "192.168.50.107", } def _run(command): try: result = subprocess.run( SSH_BASE + [command], capture_output=True, text=True, timeout=15, ) except Exception as exc: return f"Error conectando al router: {exc}" if result.returncode != 0: return f"Error del router: {result.stderr.strip()[-300:]}" return result.stdout.strip() def estado(): output = _run( "printf '%s\\n' " "'Modelo='$(nvram get productid) " "'Firmware='$(nvram get firmver).$(nvram get buildno) " "'LAN='$(nvram get lan_ipaddr) " "'WAN='$(nvram get wan0_ipaddr) " "'WiFi24='$(nvram get wl0_radio) " "'WiFi5='$(nvram get wl1_radio); uptime" ) return f"
{html.escape(output)}
" def wifi(): output = _run( "printf '%s\\n' " "'2.4GHz='$(nvram get wl0_radio) " "'5GHz='$(nvram get wl1_radio) " "'6GHz='$(nvram get wl2_radio)" ) return f"
{html.escape(output)}
" def clientes(): output = _run("cat /proc/net/arp") return f"
{html.escape(output)}
" def _reservas_actuales(text): return re.findall(r"<([^>]+)>([^>]+)>>", text or "") def _inventario(): leases = _run("cat /var/lib/misc/dnsmasq.leases") reservas = _reservas_actuales(_run("nvram get dhcp_staticlist")) by_mac = {mac.upper(): ip for mac, ip in reservas} for mac, ip in LEGACY_RESERVATIONS.items(): by_mac.setdefault(mac, ip) devices = [] for line in leases.splitlines(): fields = line.split() if len(fields) < 4 or not fields[2].startswith("192.168.50."): continue mac, ip, name = fields[1].upper(), fields[2], fields[3] by_mac.setdefault(mac, ip) devices.append((ip, mac, name if name != "*" else "pendiente-identificar")) devices.sort(key=lambda item: int(item[0].rsplit(".", 1)[1])) return devices, by_mac def inventario(): devices, _by_mac = _inventario() lines = ["IP MAC NOMBRE"] lines.extend(f"{ip:<18} {mac:<22} {name}" for ip, mac, name in devices) return f"
{html.escape(chr(10).join(lines))}
" def reservar_dhcp(): devices, by_mac = _inventario() payload = "".join(f"<{mac}>{ip}>>" for mac, ip in by_mac.items()) command = ( f"nvram set dhcp_staticlist={shlex.quote(payload)}; " "nvram commit; service restart_dnsmasq" ) result = _run(command) if result.startswith("Error "): return result return f"Reservas DHCP aplicadas: {len(by_mac)} dispositivos. Leases inventariados: {len(devices)}." def reservas(): output = _run("nvram get dhcp_staticlist") return f"
{html.escape(output)}
" def reiniciar(): return _run("reboot") if __name__ == "__main__": action = sys.argv[1] if len(sys.argv) > 1 else "estado" actions = { "estado": estado, "clientes": clientes, "wifi": wifi, "inventario": inventario, "reservar": reservar_dhcp, "reservas": reservas, } print(actions.get(action, estado)())