From 52c7b4b968190dda2d762ba1b8324b7cff994b78 Mon Sep 17 00:00:00 2001 From: MinhNN Date: Thu, 12 Mar 2026 23:55:26 +0700 Subject: [PATCH] update doc --- README.md | 9 ++++---- docs/scanner_docs.md | 50 ++++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 0d27902..deba526 100644 --- a/README.md +++ b/README.md @@ -126,15 +126,14 @@ Output: `dist\Mira_Firmware_Loader.exe` — không cần cài Python trên máy ### 1. Quét mạng (Network Scan) -`scanner.py` sử dụng chiến lược **Ping Sweep**, chỉ quét thiết bị đang online thông qua ping: +`scanner.py` sử dụng chiến lược **Ping trước → ARP sau**, đảm bảo vừa lấy được MAC vừa loại bỏ hoàn toàn lỗi thiết bị ảo do ARP cache cũ: | Giai đoạn | Mô tả | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Ping Sweep** | Gửi ping đồng thời tới toàn bộ host trong dải mạng bằng tiến trình con (đa luồng). Thiết bị có phản hồi (`returncode == 0`) sẽ được coi là online. | +| **Ping Sweep** | Gửi ping đồng thời tới toàn bộ host trong dải mạng bằng tiến trình con (đa luồng). Nhằm xác định chính xác thiết bị nào đang thực sự cấp nguồn online. | +| **ARP Lookup** | Ngay sau khi ping, query ARP table hệ điều hành (song song) _chỉ cho các IP vừa ping thành công_, lấy MAC Address chuẩn xác trước khi cache cũ hết hạn. | -*Lưu ý: Phương pháp hiện tại quét tĩnh lấy IP, bỏ qua phân giải MAC address (hiển thị N/A) nhằm giải quyết triệt để lỗi thiết bị bị cache lưa trong mạng dù đã reset/rút nguồn điện.* - -Kết quả được sort tăng dần theo IP trước khi trả về UI. +Kết quả (IP và MAC) được sort tăng dần theo IP trước khi trả về UI. ### 2. Bảng thiết bị (Device Table) diff --git a/docs/scanner_docs.md b/docs/scanner_docs.md index bb0544a..9461d9d 100644 --- a/docs/scanner_docs.md +++ b/docs/scanner_docs.md @@ -2,11 +2,13 @@ ## 1. Tổng quan -Thành phần quét IP trong `scanner.py` dò tìm và liệt kê tất cả thiết bị **đang thực sự online** trên một dải mạng (ví dụ: `192.168.1.0/24`), trả về danh sách chứa **IP** của từng thiết bị. +Thành phần quét IP trong `scanner.py` dò tìm và liệt kê tất cả thiết bị **đang thực sự online** trên một dải mạng (ví dụ: `192.168.1.0/24`), trả về danh sách chứa **IP** và **MAC Address** của từng thiết bị. -Scanner chỉ sử dụng **ICMP Ping** — thiết bị phải phản hồi ping thì mới được liệt kê. Cơ chế này đảm bảo kết quả chính xác, tránh hiện tượng hiển thị thiết bị đã ngắt kết nối do ARP cache cũ trên router/OS. +Scanner hoạt động theo cơ chế 2 bước (Ping trước → ARP sau): +1. **ICMP Ping Sweep:** Chỉ những IP có phản hồi ping mới được ghi nhận là online. +2. **ARP Lookup:** Ngay sau khi IP phản hồi ping, OS tự động cập nhật ARP cache cho IP đó. Scanner lập tức query ARP table để lấy MAC chính xác nhất. -> **Lý do loại bỏ ARP và Scapy:** Bảng ARP của hệ điều hành và router giữ cache entry trong nhiều phút, khiến thiết bị đã rút vẫn xuất hiện trong kết quả scan. Ping trực tiếp là phương pháp duy nhất xác nhận thiết bị thực sự đang hoạt động tại thời điểm scan. +> **Giải quyết vấn đề ARP cache cũ (stale entries):** Khác với phương pháp ARP scan truyền thống (`arp -a` liệt kê toàn mạng) thường dính thiết bị đã ngắt kết nối do bị cache, cách làm này **chỉ query ARP cho những IP vừa pass qua bài test ping**. Thiết bị offline sẽ rớt ở bước ping và không bao giờ được đưa vào danh sách. --- @@ -23,19 +25,27 @@ scan_network(network) │ │ │ └── return [alive IPs] │ - └── return [{"ip": ..., "mac": "N/A"}, ...] ← Sorted by IP + ├── stage_cb("mac") ← Thông báo UI bắt đầu lấy MAC + │ + ├── _get_mac_from_arp(ip) × K ← Tra MAC song song cho K IP alive + │ + └── return [{"ip": ..., "mac": "AA:BB:CC:..."}, ...] ← Sorted by IP ``` **Bước 1 — Ping Sweep** - Gọi `_ping_sweep(network)`: gửi ICMP Echo Request đồng thời tới **toàn bộ host** trong dải mạng. -- Chỉ các IP có `returncode == 0` (phản hồi thành công) mới được đưa vào kết quả. +- Chỉ các IP có `returncode == 0` (phản hồi thành công) mới được đưa vào danh sách `alive_ips`. -**Bước 2 — Trả về kết quả** +**Bước 2 — Địa chỉ MAC (ARP Lookup)** + +- Từ danh sách `alive_ips`, tạo ThreadPoolExecutor (max_workers=32) để gọi `_get_mac_from_arp(ip)` đồng thời. +- Trích xuất MAC address bằng pattern matching chéo nền tảng. + +**Bước 3 — Trả về kết quả** - Danh sách sort tăng dần theo IP: - `[{"ip": "192.168.1.2", "mac": "N/A"}, ...]` -- Trường `mac` luôn là `"N/A"` — giữ nguyên cấu trúc dict để tương thích với UI và các module khác. + `[{"ip": "192.168.1.2", "mac": "AA:BB:CC:DD:EE:FF"}, ...]` --- @@ -64,11 +74,19 @@ Windows sử dụng `CREATE_NO_WINDOW` flag để tránh mở cửa sổ console - Trả về danh sách IP (string) đã phản hồi thành công. - Gọi `progress_cb(done, total)` sau mỗi ping để UI cập nhật thanh tiến độ. +### `_get_mac_from_arp(ip)` + +- Gọi lệnh hệ điều hành để đọc ARP cache cho IP cụ thể: + - **Windows**: `arp -a ` + - **macOS / Linux**: `arp -n ` +- Sử dụng Regex để parse MAC address và trả về dưới format chuẩn `AA:BB:CC:DD:EE:FF`. +- Nếu không tìm thấy, fallback thành `"N/A"`. + ### `scan_network(network, progress_cb, stage_cb)` - Entry point chính. -- `stage_cb("ping")` thông báo UI giai đoạn hiện tại. -- Trả về `list[dict]` với format `{"ip": str, "mac": "N/A"}`, sorted theo IP tăng dần. +- `stage_cb("ping")` và `stage_cb("mac")` thông báo UI giai đoạn hiện tại. +- Trả về `list[dict]` với format `{"ip": str, "mac": str}`, sorted theo IP tăng dần. --- @@ -89,14 +107,14 @@ Windows sử dụng `CREATE_NO_WINDOW` flag để tránh mở cửa sổ console **Ưu điểm:** -- **Kết quả chính xác** — chỉ thiết bị thực sự online mới xuất hiện, không bị ảnh hưởng bởi ARP cache cũ. +- **Có đầy đủ IP và MAC**, rất hữu ích cho log và tracking lịch sử thiết bị nạp FW. +- **Không bị dính ARP cache cũ**: Do chỉ lấy MAC của các IP vừa ping thành công. - Không cần quyền Admin/Root. -- Không phụ thuộc thư viện bên ngoài (không cần Scapy, Npcap). +- Không phụ thuộc thư viện bên ngoài (không cần Npcap / Scapy phức tạp). - Tương thích đa nền tảng (Windows/macOS/Linux). -- Nhanh (~1–2s cho /24) nhờ ping toàn bộ host đồng thời. +- Cực nhanh nhờ cơ chế full-parallel. **Nhược điểm:** -- Không có thông tin MAC address. -- Thiết bị chặn ICMP (tắt ping) sẽ không bị phát hiện. -- Spawn ~254 process `ping` đồng thời trên Windows có overhead cao hơn Unix. +- Thiết bị cố tình chặn gói tin ICMP (tắt ping) sẽ không bị phát hiện. +- Ping 254 thiết bị cùng lúc bằng tiến trình con (`subprocess`) trên Windows có overhead hệ thống cao hơn Unix.