Khởi động lại modem cáp quang + Wi-Fi FPT do một công ty nào đó của Trung Quốc sản xuất. Dù modem cũng hỗ trợ Reboot Timer nhưng có vấn đề gì đó khiến modem không được ổn định khi bật tính năng này.

Ví dụ sau dành cho thiết bị Modem + Wi-Fi có tên Internet Hub AC1000C (Model: G-97RG6M) hỗ trợ 4 đầu ra LAN, Wi-Fi băng tần kép 2.4GHz (802.11b/g/n) và 5GHz (802.11 a/n/ac) – tôi được “tặng” khi đăng ký gói cáp quang FPT.
Dù thiết bị hoạt động khá ổn định nhưng tôi vẫn muốn khởi động lại thiết bị này mỗi tuần cho tươi mới. Vì modem nào cũng vậy, chạy lâu lâu rồi kiểu gì cũng sẽ có vấn đề.
Cách làm dưới đây về nguyên tắc không hề phụ thuộc bạn đang dùng modem nào bởi chúng chỉ khác nhau về giao diện web và/hoặc cú pháp dòng lệnh (nếu có). Hãy thay đổi tùy theo thiết bị bạn đang có.
Khởi động lại bằng SSH
Modem này hỗ trợ SSH. Để bật SSH, ta đăng nhập vào giao diện web tại địa chỉ http://192.168.1.1 như sau:

Vào mục Security Setup › SSH, bật (enable) Local SSH lên, đừng có bật Remote SSH vì khá mạo hiểm. Cài đặt Username và Password đăng nhập (nên khác với user và password đăng nhập giao diện web).

Bạn có thể thử nghịch ngợm với SSH terminal này bằng lệnh ssh
.
ssh icreativ@192.168.1.1
Lưu ý: Nếu bạn nhận được thông báo sau:
Unable to negotiate with 192.168.1.1 port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1,diffie-hellman-group14-sha1
Nguyên nhân là do SSH phiên bản mới mặc định không hỗ trợ thuật toán mã hóa “cũ”. Hãy thêm đoạn sau vào .ssh/config
rồi thử lại.
Host 192.168.1.1 KexAlgorithms +diffie-hellman-group1-sha1
SSH của modem không hỗ trợ SSH key và phải thao tác vài bước mới đến được shell để gọi lệnh reboot
. Để tự động hóa, ta có thể dùng lệnh expect
như sau:
reboot-modem.exp
#!/usr/bin/expect # reboot-modem.exp # @author: Nguyen Hong Hai # Your username@host spawn ssh icreativ@192.168.1.1 expect "password: " # Your SSH password goes here send -- "my-ugly-password\r" expect "#ONT>" # Get into shell send "system/shell\r" expect "#ONT/system/shell>" # Perform the reboot command send "/sbin/reboot\r" expect eof
Chú ý ký tự \r
(tương ứng phím Enter) sau các chuỗi mỗi lần gọi send
.
Chạy script như sau:
expect ./reboot-modem.exp
Hoặc phân quyền executable cho script và chạy thẳng lệnh này luôn:
chmod +x reboot-modem.exp
./reboot-modem.exp
Khởi động lại bằng headline browser
Nếu không muốn dùng đến SSH thì ta vẫn còn một cách khác là thao tác trên giao diện web. Cụ thể chúng ta sẽ giả lập kết quả sau khi nút Reboot dưới đây bị ấn. Tôi định sử dụng Nightmare.js.

Tuy nhiên điều khó khăn khi dùng nightmare js trong trường hợp này là toàn bộ giao diện bị nhúng trong một FRAME và có cơ chế bảo vệ không cho load riêng trang trong FRAME. Do giới hạn của công cụ, tôi không thể dò đến các nút để thao tác được.
Tuy nhiên sau khi xem qua mã nguồn JS, hóa ra quy trình reboot là thực hiện một POST request đến địa chỉ /GponForm/reboot_XForm
kèm theo một biến XWebPageName
mang giá trị reboot
. Tất nhiên điều này chỉ hiệu lực khi ta đã login thành công.
Vì thế script sau sẽ thực hiện hai bước:
- Đăng nhập giao diện web bằng Nightmare JS.
- Thực hiện POST request với XMLHttpRequest.
Yêu cầu trước hết bạn cần cài đặt Node.Js, sau đó cài đặt NightmareJS như sau:
mkdir reboot-modem cd reboot-modem npm i nightmare --save-dev
Mã nguồn chương trình khởi động modem bằng JavaScript. Lưu ý thay USERNAME
và PASSWORD
bằng tài khoản đăng nhập modem qua web.
reboot-modem.js
/** * reboot-modem.js * @author Nguyen Hong Hai */ const LOGINURL = 'http://192.168.1.1/login.html'; const USERNAME = 'admin'; const PASSWORD = 'password'; const Nightmare = require('nightmare'); const nightmare = Nightmare({ show: true }); nightmare .goto(LOGINURL) // Perform the login operation .type('#username', USERNAME) .type('#password', PASSWORD) .click('#btn_login') .wait('#contentfrm') // Perform a POST request to reboot the modem .evaluate(() => { return new Promise((resolve, reject) => { var oXHR = new XMLHttpRequest(); oXHR.open("POST", "/GponForm/reboot_XForm", true); oXHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); oXHR.onreadystatechange = function() { if (oXHR.readyState === 4) { if (oXHR.status === 200) { resolve("Success!"); } else { reject(oXHR.statusText); } } } oXHR.send("XWebPageName=reboot"); }); }) .end() .then(console.log) .catch(error => { console.error('Error:', error) });
Chạy script này như sau:
cd reboot-modem node ./reboot-modem.js
Sau đó việc cuối cùng là tôi đặt (một trong hai) lệnh trên vào crontab
trên thiết bị Raspberry Pi để lên lịch gọi mỗi tuần.
