Khởi động lại (reboot) modem cáp quang FPT

Tự động khởi động lại modem cáp quang + Wi-Fi tôi được “tặng” khi đăng ký gói cáp quang FPT.

Khởi động lại (reboot) modem cáp quang FPT
Khởi động lại (reboot) modem Internet Hub AC1000C (G-97RG6M)

Thiết bị Modem + Wi-Fi có tên Internet Hub AC1000C (Model: GPON ONT 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) – do Huawei sản xuất nhưng không đề tên.

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 đề.

Dù modem cũng hỗ trợ tính năng Reboot Timer nhưng có vấn đề gì đó khiến modem không được ổn định sau khi tôi bật tính năng này.

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ó.

Tôi sẽ dùng một máy tính Raspberry Pi của tôi để định kỳ reboot modem từ xa.

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:

Đăng nhập vào modem (địa chỉ và tên user có thể khác với thiết bị của bạn)

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 UsernamePassword đăng nhập (nên khác với user và password đăng nhập giao diện web).

Cấu hình SSH trên modem

Bạn có thể thử nghịch ngợm với SSH terminal này bằng lệnh ssh. Ví dụ ở đây user là icreativ và IP modem là 192.168.1.1.

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 client phiên bản mới mặc định không hỗ trợ thuật toán mã hóa Diffie-Hellman là một thuật toán có tính bảo mật không còn cao so với công nghệ thời nay. 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

set USERNAME "icreativ"
set PASSWORD "password"
set ROUTERIP "192.168.1.1"

# Your username@host
spawn ssh $USERNAME@$ROUTERIP
expect "password: "

# Your SSH password goes here
send -- "$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 headless 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 Puppeteer.

Nút khởi động (reboot) trên giao diện Web

Tuy nhiên điều khó khăn khi dùng Puppeteer 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 Puppeteer.
  • 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 Puppeteer như sau:

mkdir reboot_modem
cd reboot_modem
npm i puppeteer-core --save-dev

Mã nguồn chương trình khởi động modem bằng JavaScript. Lưu ý thay USERNAMEPASSWORD bằng tài khoản đăng nhập modem qua web.

reboot_modem/index.js

/**
 * reboot_modem/index.js
 * @author Nguyen Hong Hai
 */
const LOGINURL = "http://192.168.1.1/login.html";
const USERNAME = "admin";
const PASSWORD = "password";

const puppeteer = require("puppeteer-core");

(async () => {
    const browser = await puppeteer.launch({
        // Path to the Chromium browser binary on Raspberry Pi
        executablePath: "/usr/bin/chromium-browser"
    });
    try {
        const page = await browser.newPage();
        await page.goto(LOGINURL, {waitUntil: "networkidle2"});
        await page.waitForSelector("#username");
        await page.type("#username", USERNAME);
        await page.type("#password", PASSWORD);
        await page.click("#btn_login");
        await page.waitForSelector("#contentfrm");
        await page.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();
                        } else {
                            reject(oXHR.statusText);
                        }
                    }
                }
                oXHR.send("XWebPageName=reboot");
            });
        });
    } catch (error) {
        console.error("Error:", error)
    } finally {
        await browser.close();
    }
})();

Chạy script này như sau:

cd reboot_modem
node ./index.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.

Cấu hình crontab khởi động lại modem 3 giờ sáng thứ 2 hàng tuần (dòng cuối)

Phản hồi về bài viết

Cùng thảo luận chút nhỉ!

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.