diff --git a/napalm_procurve/procurve.py b/napalm_procurve/procurve.py index f63e78a..ce8b816 100644 --- a/napalm_procurve/procurve.py +++ b/napalm_procurve/procurve.py @@ -592,50 +592,32 @@ class ProcurveDriver(ConfigLifecycleMixin, SwitchDriver): Used as fallback when the REST API does not expose the config endpoint (e.g. HP 2530 / YA firmware with Mocana SSH). - Uses a raw socket with settimeout() so the timeout covers ALL phases of - the SSH handshake (TCP connect, banner, KEX, auth) — not just TCP connect. - This is the only reliable way to prevent a hanging KEX from blocking - indefinitely inside the poll task. + Uses SSHClient.connect() with the same approach as the netOrk SSH + console link (_paramiko_connect in _helpers.py) — no algorithm + overrides, plain password auth, 15-second banner timeout. """ - import socket as _socket - import paramiko - _FALLBACK_TIMEOUT = 8 # seconds — covers the entire SSH session - - _LEGACY_KEX = [ - "diffie-hellman-group1-sha1", - "diffie-hellman-group14-sha1", - "diffie-hellman-group14-sha256", - ] + _TIMEOUT = 15 try: - sock = _socket.create_connection( - (self.hostname, self.port or 22), - timeout=_FALLBACK_TIMEOUT, - ) - sock.settimeout(_FALLBACK_TIMEOUT) # applies to all recv/send including KEX - - transport = paramiko.Transport(sock) - transport.get_security_options().kex = _LEGACY_KEX - transport.connect( + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect( + hostname=self.hostname, + port=self.port or 22, username=self.username, password=self.password, + timeout=_TIMEOUT, + banner_timeout=_TIMEOUT, + auth_timeout=_TIMEOUT, + look_for_keys=False, + allow_agent=False, ) - - channel = transport.open_session() - channel.settimeout(_FALLBACK_TIMEOUT) - channel.exec_command("show running-config") - - chunks: list[bytes] = [] - while True: - data = channel.recv(4096) - if not data: - break - chunks.append(data) - - transport.close() - return b"".join(chunks).decode("utf-8", errors="replace") + _, stdout, _ = client.exec_command("show running-config", timeout=_TIMEOUT) + config = stdout.read().decode("utf-8", errors="replace") + client.close() + return config except Exception as exc: logger.warning("SSH config fallback failed for %s: %s", self.hostname, exc) return ""