bug in zyxel

This commit is contained in:
2026-08-22 19:54:38 +02:00
parent 90671d0b9b
commit d43b375d73
6 changed files with 166 additions and 7 deletions
+73 -6
View File
@@ -2,14 +2,18 @@
from __future__ import annotations
import argparse
import base64
import json
import os
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from urllib.parse import urlsplit
import requests
import yaml
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import pad, unpad
@@ -145,13 +149,24 @@ class ZyxelRouter:
result = self.dal_get(self.hosts_oid)
if result.get("result") not in (None, "ZCFG_SUCCESS"):
raise ZyxelError(f"lanhosts query failed: {result.get('result')}")
objects = result.get("Object", [])
if isinstance(objects, dict):
objects = [objects]
def host_records(value: Any):
"""Yield host dictionaries from flat and nested DAL response shapes."""
if isinstance(value, dict):
if any(
key in value
for key in ("PhysAddress", "physAddress", "MACAddr", "MacAddress")
):
yield value
return
for child in value.values():
yield from host_records(child)
elif isinstance(value, list):
for child in value:
yield from host_records(child)
hosts: list[LanHost] = []
for item in objects:
if not isinstance(item, dict):
continue
for item in host_records(result.get("Object", [])):
raw_mac = next((item.get(key) for key in ("PhysAddress", "physAddress", "MACAddr", "MacAddress") if item.get(key)), None)
if not raw_mac:
continue
@@ -182,3 +197,55 @@ class ZyxelRouter:
self._session_key = None
self._aes_key = None
self.session.close()
def _load_cli_config(path: Path) -> tuple[dict[str, Any], str]:
try:
with path.open(encoding="utf-8") as stream:
root = yaml.safe_load(stream)
arrival = root["arrival_detection"]
return arrival["zyxel"], str(arrival["device"]["mac"])
except (OSError, TypeError, KeyError, yaml.YAMLError) as error:
raise ZyxelError(f"could not load configuration from {path}: {error}") from error
def main() -> int:
parser = argparse.ArgumentParser(
description="Check whether a MAC address is connected to the configured Zyxel router."
)
parser.add_argument(
"--config",
type=Path,
default=Path(__file__).resolve().parents[1] / "service.yaml",
help="service configuration file (default: project service.yaml)",
)
parser.add_argument(
"--mac",
help="MAC address to check (default: arrival_detection.device.mac)",
)
args = parser.parse_args()
try:
config, configured_mac = _load_cli_config(args.config)
mac = normalize_mac(args.mac or configured_mac)
router = ZyxelRouter(
config["host"],
config["username"],
config["password"],
timeout=float(config.get("timeout", 10)),
verify_tls=bool(config.get("verify_tls", True)),
hosts_oid=str(config.get("hosts_oid", "lanhosts")),
)
try:
connected = router.is_connected(mac)
finally:
router.close()
print(f"{mac} {'connected' if connected else 'absent'}")
return 0
except (ValueError, ZyxelError) as error:
print(f"error: {error}", file=sys.stderr)
return 2
if __name__ == "__main__":
raise SystemExit(main())