fix bug loader fw SSH, update doc, update scan ip ( scan nhanh hơn )

This commit is contained in:
2026-03-08 16:25:14 +07:00
parent f8ce6f5831
commit ef363ac61d
5 changed files with 186 additions and 136 deletions

View File

@@ -12,15 +12,22 @@ import os
import time
import paramiko
from scp import SCPClient
import random
def _create_ssh_client(ip, user, password, timeout=10):
"""Create an SSH client with auto-accept host key policy."""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, password=password, timeout=timeout,
look_for_keys=False, allow_agent=False)
return client
def _create_ssh_client(ip, user, password, timeout=15):
"""Create an SSH client with auto-accept host key policy, including retries."""
for attempt in range(3):
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, password=password, timeout=timeout,
look_for_keys=False, allow_agent=False)
return client
except Exception as e:
if attempt == 2:
raise e
time.sleep(1)
import telnetlib
@@ -30,6 +37,9 @@ def set_device_password(ip, user="root", old_password="", new_password="admin123
"""
Set device password via Telnet (if raw/reset) or SSH.
"""
# Jitter to avoid hammering the network with many concurrent connections
time.sleep(random.uniform(0.1, 1.5))
if status_cb:
status_cb("Checking Telnet port for raw device...")
@@ -63,53 +73,63 @@ def set_device_password(ip, user="root", old_password="", new_password="admin123
time.sleep(3)
return "DONE"
except ConnectionRefusedError:
# Port 23 đóng -> Tức là thiết bị đã có Pass và đã bật SSH, chuyển qua luồng mồi mật khẩu cũ
pass
except Exception as e:
# Các lỗi timeout khác có thể do ping không tới
return f"FAIL: Telnet check -> {e}"
# Bất kỳ lỗi Telnet nào (ConnectionRefused, Timeout, BrokenPipe...)
# đều có nghĩa là Telnet không truy cập được hoặc bị đóng ngang.
# Chuyển qua luồng kết nối SSH.
pass
# 2. Rơi xuống luồng SSH nếu thiết bị cũ (cổng Telnet đóng)
# 2. Rơi xuống luồng SSH nếu thiết bị cũ (cổng Telnet đóng hoặc lỗi)
if status_cb:
status_cb("Connecting SSH for password update...")
try:
client = _create_ssh_client(ip, user, old_password, timeout=5)
except Exception as e:
return f"FAIL: Cannot connect SSH (Old pass incorrect?) — {e}"
last_error = None
for attempt in range(3):
try:
client = _create_ssh_client(ip, user, old_password, timeout=10)
if status_cb:
status_cb("Setting password via SSH...")
try:
if status_cb:
status_cb("Setting password via SSH...")
shell = client.invoke_shell()
time.sleep(1)
if shell.recv_ready():
shell.recv(65535)
shell = client.invoke_shell()
time.sleep(1)
if shell.recv_ready():
shell.recv(65535)
shell.send("passwd\n")
time.sleep(2)
shell.send(f"{new_password}\n")
time.sleep(1)
shell.send(f"{new_password}\n")
time.sleep(2)
shell.send("passwd\n")
time.sleep(2)
shell.send(f"{new_password}\n")
time.sleep(1)
shell.send(f"{new_password}\n")
time.sleep(2)
if shell.recv_ready():
shell.recv(65535)
if shell.recv_ready():
shell.recv(65535)
shell.send("exit\n")
time.sleep(0.5)
shell.close()
client.close()
shell.send("exit\n")
time.sleep(0.5)
shell.close()
if status_cb:
status_cb("Password set ✓")
return "DONE"
except Exception as e:
return f"FAIL: {e}"
finally:
client.close()
if status_cb:
status_cb("Password set ✓")
return "DONE"
except paramiko.AuthenticationException as e:
# Authentication means wrong password, retrying won't help here
if 'client' in locals() and client:
client.close()
return f"FAIL: Cannot connect SSH (Old pass incorrect?) — {e}"
except Exception as e:
last_error = e
if 'client' in locals() and client:
try: client.close()
except: pass
# Errno 64 or 113 usually means 'Host is down' or 'No route to host'.
# It can be a transient switch issue. Wait a bit and retry.
time.sleep(2)
return f"FAIL: Cannot connect SSH after 3 attempts — {last_error}"
def flash_device_ssh(ip, firmware_path, user="root", password="admin123a",
@@ -131,6 +151,10 @@ def flash_device_ssh(ip, firmware_path, user="root", password="admin123a",
# ═══════════════════════════════════════════
# STEP 0: Set password (optional)
# ═══════════════════════════════════════════
if not set_passwd:
# Jitter here if we skip set_passwd
time.sleep(random.uniform(0.1, 1.5))
if set_passwd:
result = set_device_password(ip, user, "", password, status_cb)
if result.startswith("FAIL"):
@@ -170,12 +194,21 @@ def flash_device_ssh(ip, firmware_path, user="root", password="admin123a",
filename = os.path.basename(firmware_path)
remote_path = f"/tmp/{filename}"
try:
scp_client = SCPClient(client.get_transport(), socket_timeout=300)
scp_client.put(firmware_path, remote_path)
scp_client.close()
except Exception as e:
return f"FAIL: SCP upload failed — {e}"
upload_success = False
last_error = None
for attempt in range(3):
try:
scp_client = SCPClient(client.get_transport(), socket_timeout=350)
scp_client.put(firmware_path, remote_path)
scp_client.close()
upload_success = True
break
except Exception as e:
last_error = e
time.sleep(1.5)
if not upload_success:
return f"FAIL: SCP upload failed (Check Network) — {last_error}"
time.sleep(2)