200 lines
11 KiB
Markdown
200 lines
11 KiB
Markdown
# ⚡ Mira Firmware Loader
|
||
|
||
Công cụ desktop dùng để **scan, phát hiện và flash firmware hàng loạt** cho các thiết bị OpenWrt trong mạng LAN.
|
||
|
||
> **Tech stack:** Python 3.9+ · PyQt6 · Paramiko/SCP · Scapy · Requests · PyInstaller
|
||
> **Phiên bản:** `1.1.3`
|
||
|
||
---
|
||
|
||
## 📁 Cấu trúc dự án
|
||
|
||
```text
|
||
Mira_Firmware_Loader/
|
||
├── main.py # UI chính (PyQt6)
|
||
├── version.txt # Số phiên bản ứng dụng
|
||
├── requirements.txt # Danh sách dependencies
|
||
├── core/
|
||
│ ├── scanner.py # Quét thiết bị mạng đa lớp (Ping sweep + ARP + Scapy)
|
||
│ ├── workers.py # ScanThread — chạy scanner trong background thread
|
||
│ ├── api_flash.py # Flash firmware qua LuCI HTTP API
|
||
│ ├── ssh_utils.py # SSH/SCP transport helpers dùng chung
|
||
│ ├── ssh_new_flash.py # Luồng SSH cho chế độ Nạp Mới (Telnet → set passwd → SSH)
|
||
│ ├── ssh_update_flash.py # Luồng SSH cho chế độ Update (SSH trực tiếp)
|
||
│ ├── flash_new_worker.py # NewFlashThread — QThread điều phối Nạp Mới FW
|
||
│ └── flash_update_worker.py # UpdateFlashThread — QThread điều phối Update FW
|
||
├── ui/
|
||
│ ├── components.py # Custom Qt Widgets (CollapsibleGroupBox)
|
||
│ └── styles.py # Stylesheet toàn ứng dụng
|
||
├── utils/
|
||
│ ├── network.py # Helper IP / network (get_local_ip, get_default_network)
|
||
│ └── system.py # Lấy thông tin máy, resource path cho PyInstaller
|
||
├── docs/
|
||
│ ├── api_flash_docs.md # Tài liệu kỹ thuật LuCI API flash
|
||
│ ├── load_fw_ssh_docs.md # Tài liệu kỹ thuật SSH flash (cả 2 luồng)
|
||
│ └── scanner_docs.md # Tài liệu kỹ thuật scanner
|
||
├── run.sh # Script khởi chạy (macOS/Linux)
|
||
├── run.bat # Script khởi chạy (Windows)
|
||
└── build_windows.bat # Script đóng gói thành .exe (Windows, PyInstaller)
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Cài đặt & Chạy
|
||
|
||
### Yêu cầu
|
||
|
||
- Python **3.9+**
|
||
- Thư viện: `PyQt6`, `scapy`, `requests`, `paramiko`, `scp`, `pyinstaller` (để build)
|
||
- _Windows:_ Cài [Npcap](https://npcap.com/) để Scapy có thể gửi ARP broadcast (không bắt buộc — có fallback)
|
||
|
||
### Khởi chạy nhanh
|
||
|
||
**macOS / Linux:**
|
||
|
||
```bash
|
||
./run.sh
|
||
```
|
||
|
||
**Windows:**
|
||
|
||
```bat
|
||
run.bat
|
||
```
|
||
|
||
> Script tự tạo `venv` và cài dependencies nếu chưa có.
|
||
|
||
### 📦 Build file chạy độc lập (.exe) cho Windows
|
||
|
||
```bat
|
||
build_windows.bat
|
||
```
|
||
|
||
Output: `dist\Mira_Firmware_Loader.exe` — không cần cài Python trên máy đích.
|
||
|
||
---
|
||
|
||
## 🏗 Kiến trúc hệ thống
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ main.py (UI) │
|
||
│ │
|
||
│ Machine Info │ Firmware Selector │ Network Scan │
|
||
│ ───────────────────────────────────────────────────── │
|
||
│ Device Table [ ] IP │ MAC │ Status │
|
||
│ ───────────────────────────────────────────────────── │
|
||
│ Flash Controls │
|
||
│ Flash Mode: [ New Flash | Update Firmware ] │
|
||
│ Method: [ API (LuCI) | SSH (paramiko) ] │
|
||
│ Concurrent devices: [SpinBox] │
|
||
│ [ ⚡ FLASH SELECTED DEVICES ] │
|
||
└────────────────────────┬─────────────────────────────────┘
|
||
│
|
||
┌──────────────┼──────────────┐
|
||
│ │
|
||
┌──────▼──────┐ ┌────────▼────────────────┐
|
||
│ scanner.py │ │ Flash Workers │
|
||
│ │ │ │
|
||
│ 1. Ping │ │ NewFlashThread │
|
||
│ Sweep │ │ ├─ method=api │
|
||
│ 2. arp -a │ │ │ └── api_flash.py │
|
||
│ 3. Scapy │ │ └─ method=ssh │
|
||
│ ARP │ │ └── ssh_new_flash │
|
||
└─────────────┘ │ │
|
||
│ UpdateFlashThread │
|
||
│ └─ ssh_update_flash.py │
|
||
└─────────────────────────┘
|
||
│
|
||
┌──────────▼──────────┐
|
||
│ ssh_utils.py │
|
||
│ (Transport Layer) │
|
||
│ _create_ssh_client │
|
||
│ _upload_firmware │
|
||
│ _verify_firmware │
|
||
│ _sync_and_sysupgr │
|
||
└─────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Luồng hoạt động chi tiết
|
||
|
||
### 1. Quét mạng (Network Scan)
|
||
|
||
`scanner.py` dùng chiến lược 3 lớp, đảm bảo phát hiện đầy đủ mà không cần quyền Root:
|
||
|
||
| Giai đoạn | Mô tả |
|
||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||
| **Ping Sweep** | Gửi ping đồng thời tới toàn bộ host trong dải `/24` (tất cả cùng lúc, không batching) để đánh thức thiết bị và điền ARP cache |
|
||
| **ARP Table** | Đọc `arp -a` bằng regex, hỗ trợ cả định dạng Windows (`cc-2d-...`) và macOS/Linux (`aa:bb:...`) |
|
||
| **Scapy ARP** | Chạy **song song** với ARP Table — gửi ARP broadcast để lấp khoảng trống. Yêu cầu Npcap (Windows) hoặc root (Linux); tự động bỏ qua nếu không khả dụng |
|
||
|
||
Kết quả được merge theo IP và sort tăng dần trước khi trả về UI.
|
||
|
||
### 2. Bảng thiết bị (Device Table)
|
||
|
||
- Hiển thị cột: checkbox, IP, MAC, Status
|
||
- Mặc định ẩn gateway và IP máy tính đang chạy (có thể bật "Show all")
|
||
- Thiết bị đã flash trong session được đánh dấu "Already Flashed" và tự bỏ tick
|
||
|
||
### 3. Flash Firmware
|
||
|
||
Có 2 chế độ và 2 method, tổng cộng 3 luồng thực thi khác nhau:
|
||
|
||
#### Chế độ `New Flash` — dùng cho thiết bị vừa reset cứng
|
||
|
||
| Method | Luồng | Mô tả |
|
||
| -------------- | ------------------ | ------------------------------------------------------------------------------------------- |
|
||
| **API (LuCI)** | `api_flash.py` | Đăng nhập LuCI → upload firmware → Proceed. Hỗ trợ Barrier Breaker 14.07 và OpenWrt mới hơn |
|
||
| **SSH** | `ssh_new_flash.py` | Kết nối Telnet → đặt password mới → SSH → SCP upload → sysupgrade |
|
||
|
||
**Luồng SSH – New Flash chi tiết:**
|
||
|
||
1. Telnet port 23 (thiết bị vừa reset, chưa có pass)
|
||
2. Đặt password `admin123a` qua lệnh `passwd`
|
||
3. SSH vào với password vừa đặt
|
||
4. SCP upload firmware lên `/tmp/`
|
||
5. Verify file tồn tại
|
||
6. `sync && sysupgrade -F -v -n` → thiết bị reboot (connection drop = DONE)
|
||
|
||
#### Chế độ `Update Firmware` — dùng cho thiết bị đang chạy OpenWrt
|
||
|
||
Luồng `ssh_update_flash.py`, SSH trực tiếp (không qua Telnet):
|
||
|
||
1. SSH kết nối với `root` / `admin123a` (fallback: `admin`)
|
||
2. SCP upload firmware lên `/tmp/`
|
||
3. Verify file tồn tại
|
||
4. `sync && sysupgrade -F -v -n` → thiết bị reboot
|
||
|
||
> ⚠️ Update Mode hiển thị cảnh báo nếu IP thiết bị khác `192.168.11.102` và yêu cầu xác nhận.
|
||
|
||
### 4. Xử lý song song
|
||
|
||
| Tham số | Mô tả |
|
||
| ---------------------- | ------------------------------------------------------------------------ |
|
||
| **Concurrent devices** | Số thiết bị flash đồng thời (`ThreadPoolExecutor`). `0` = không giới hạn |
|
||
|
||
---
|
||
|
||
## ⚙️ Cấu hình mặc định
|
||
|
||
| Tham số | Giá trị mặc định | Mô tả |
|
||
| ---------------------- | ------------------------------------ | --------------------------------- |
|
||
| **Network** | Tự suy ra từ local IP (`x.x.x.0/24`) | Dải mạng để quét |
|
||
| **Flash Mode** | `New Flash` | Nạp mới hoặc Update |
|
||
| **Method** | `API (LuCI)` | Phương thức flash cho New Flash |
|
||
| **SSH User** | `root` | Hardcoded, không hiển thị trên UI |
|
||
| **SSH Password** | `admin123a` | Hardcoded, không hiển thị trên UI |
|
||
| **Concurrent devices** | `10` | Số luồng flash song song |
|
||
| **Show all** | Tắt | Ẩn gateway và IP máy host |
|
||
|
||
---
|
||
|
||
## 🔒 Lưu ý bảo mật & Quyền
|
||
|
||
- **Scapy (chế độ sâu):** Cần Npcap (Windows) hoặc `sudo` (macOS/Linux). App vẫn hoạt động mà không cần quyền Admin nhờ fallback Ping Sweep + `arp -a`.
|
||
- **CREATE_NO_WINDOW:** Khi gọi subprocess (`ping`, `arp`), ứng dụng dùng flag `CREATE_NO_WINDOW` trên Windows để ngăn cửa sổ console hiện ra.
|
||
- **HTTP thuần:** Firmware được upload qua HTTP (không HTTPS). Chỉ dùng trong mạng LAN nội bộ, không nên dùng trên mạng mở.
|
||
- **Credentials cố định:** SSH credentials (`root`/`admin123a`) được hardcode trong `flash_update_worker.py` và truyền từ `main.py`, không hiển thị trên UI.
|