158 lines
4.3 KiB
Python
158 lines
4.3 KiB
Python
"""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"<pre>{html.escape(output)}</pre>"
|
|
|
|
|
|
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"<pre>{html.escape(output)}</pre>"
|
|
|
|
|
|
def clientes():
|
|
output = _run("cat /proc/net/arp")
|
|
return f"<pre>{html.escape(output)}</pre>"
|
|
|
|
|
|
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"<pre>{html.escape(chr(10).join(lines))}</pre>"
|
|
|
|
|
|
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"<pre>{html.escape(output)}</pre>"
|
|
|
|
|
|
def control_parental():
|
|
try:
|
|
from asus_api_control import parental_status
|
|
return f"<pre>{html.escape(parental_status())}</pre>"
|
|
except RuntimeError as exc:
|
|
return f"<pre>{html.escape(str(exc))}</pre>"
|
|
except Exception:
|
|
pass
|
|
keys = (
|
|
"yadns_enable_x",
|
|
"yadns_mode",
|
|
"yadns_clientlist",
|
|
"bwdpi_enable",
|
|
"bwdpi_rulelist",
|
|
"keyword_rulelist",
|
|
"url_rulelist",
|
|
"time_zone",
|
|
)
|
|
lines = []
|
|
for key in keys:
|
|
lines.append(f"{key}={_run(f'nvram get {key}')}")
|
|
return f"<pre>{html.escape(chr(10).join(lines))}</pre>"
|
|
|
|
|
|
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,
|
|
"parental": control_parental,
|
|
}
|
|
print(actions.get(action, estado)())
|