+проверка микротика
This commit is contained in:
parent
5f1bc35579
commit
a6f8722ad3
2 changed files with 66 additions and 1 deletions
|
|
@ -32,6 +32,7 @@ from .ssh_client import (
|
|||
fetch_slave_config,
|
||||
get_ip_neighbors_multi,
|
||||
ssh_run_multi,
|
||||
verify_is_mikrotik,
|
||||
)
|
||||
from .types import DeviceAction, DiscoveredDevice, DiscoveryResult, ProgressCallback
|
||||
|
||||
|
|
@ -811,7 +812,15 @@ async def _discover_mikrotik(
|
|||
logger.info("[discovery] MikroTik: no IP found via SSH_CLIENT")
|
||||
return
|
||||
|
||||
logger.info("[discovery] MikroTik found at %s", mikrotik_ip)
|
||||
logger.info("[discovery] MikroTik candidate: %s — verifying...", mikrotik_ip)
|
||||
await _emit("disc_action", {"message": f"Проверка MikroTik {mikrotik_ip} (WinBox/SSH)..."})
|
||||
is_mikrotik = await verify_is_mikrotik(mikrotik_ip, ssh_port, ssh_options)
|
||||
if not is_mikrotik:
|
||||
logger.info("[discovery] %s — NOT a MikroTik (WinBox and SSH banner check failed), skipping", mikrotik_ip)
|
||||
await _emit("disc_action", {"message": f"{mikrotik_ip} — не MikroTik, пропускаем"})
|
||||
return
|
||||
|
||||
logger.info("[discovery] MikroTik confirmed at %s", mikrotik_ip)
|
||||
await _emit("disc_infra_found", {"type": "mikrotik", "ip": mikrotik_ip})
|
||||
try:
|
||||
existing = (await db.execute(
|
||||
|
|
|
|||
|
|
@ -177,6 +177,62 @@ async def open_ssh_tunnel(
|
|||
raise last_exc
|
||||
|
||||
|
||||
# ── MikroTik verification ─────────────────────────────────────────────────────
|
||||
|
||||
async def verify_is_mikrotik(
|
||||
host: str,
|
||||
ssh_port: int = 22,
|
||||
ssh_options: list | None = None,
|
||||
timeout: float = 3.0,
|
||||
) -> bool:
|
||||
"""Check whether host is actually a MikroTik RouterOS device.
|
||||
|
||||
Two independent probes are tried (first positive result wins):
|
||||
1. TCP connect to port 8291 (WinBox) — exclusively used by MikroTik.
|
||||
2. SSH banner check — RouterOS advertises "ROSSSH" as its SSH version.
|
||||
|
||||
Returns True if either probe confirms MikroTik, False otherwise.
|
||||
"""
|
||||
# Probe 1: WinBox port 8291 (MikroTik-exclusive)
|
||||
try:
|
||||
reader, writer = await asyncio.wait_for(
|
||||
asyncio.open_connection(host, 8291), timeout=timeout
|
||||
)
|
||||
writer.close()
|
||||
try:
|
||||
await writer.wait_closed()
|
||||
except Exception:
|
||||
pass
|
||||
logger.info("[discovery] %s — MikroTik confirmed via WinBox port 8291", host)
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Probe 2: SSH banner
|
||||
if ssh_options:
|
||||
for opt in ssh_options:
|
||||
try:
|
||||
kwargs = _build_connect_kwargs(host, ssh_port, opt)
|
||||
kwargs["connect_timeout"] = int(timeout)
|
||||
async with asyncssh.connect(**kwargs) as conn:
|
||||
banner = (conn.get_extra_info("server_version") or "").lower()
|
||||
if "rosssh" in banner or "mikrotik" in banner:
|
||||
logger.info(
|
||||
"[discovery] %s — MikroTik confirmed via SSH banner: %s", host, banner
|
||||
)
|
||||
return True
|
||||
logger.info(
|
||||
"[discovery] %s — SSH connected but banner does not match MikroTik: %s",
|
||||
host, banner,
|
||||
)
|
||||
return False # Connected successfully — definitely not MikroTik
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
logger.info("[discovery] %s — could not verify MikroTik (no probe succeeded)", host)
|
||||
return False
|
||||
|
||||
|
||||
# ── Internal helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
def _parse_neigh_output(stdout: str) -> list[str]:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue