跳到主要内容
  1. 博客/

诺基亚贝尔XG-040G-MD光猫更换

·6 分钟
声明: 此文非原创,在此感谢在恩山论坛的各位大佬

准备工作 #

  • 先问装维确认线路是否支持XG-PON(万兆)
  • 记录vlanid,宽带账密,以及认证所需的loid+password(根据省份)
  • 具体认证方式不确定,江西移动gpon光猫更换,需要sn和password

详细步骤 #

1. 恢复出厂 #

先把诺基亚贝尔XG-040G-MD光猫恢复出厂设置,开机状态下按住复位键20秒,直到光猫灯全部闪几次后会自动重启。

2. 光猫配置(在拔掉光纤状态下执行) #

① 选择省份界面 http://192.168.1.1/opid_setting.cgi,选择地区,光猫会自动重启。

② 开启telnet:登录超级用户:CMCCAdmin,密码:aDm8H%MdA,在超级用户的状态下访问 http://192.168.1.1/system.cgi?telnet

③ 开启ftp,sma功能:在超级用户下应用->家庭存储找到存储ftp和Samba两个选项打勾

④ telnet登录:使用 telnet 协议连接光猫,通过普通用户登录(光猫背面铭牌处)后以 su user_ftp身份登录,密码和普通账户密码相同, 输入su获取root权限

具体:

在启用或关闭Windows功能中勾选Telnet Client(Telnet 客户端)

打开cmd

  • telnet 192.168.1.1
  • su user_ftp
  • su

⑤ 配置光猫,在上一步进入的telnet运行

修改root密码:

cfgcli -s InternetGatewayDevice.DeviceInfo.X_CT-COM_ServiceManage.SuPassword aDm8H%MdA

修改超级管理员密码:

cfgcli -s InternetGatewayDevice.DeviceInfo.X_CT-COM_TeleComAccount.Password aDm8H%MdA
修改MAC地址和设备序列号(如需要)
  • ritool set YPSerialNum 8300012110BC046384
    ritool set MACAddress 3c:bd:69:6b:6d:7a (MAC的英文要小写)
    ritool set G984Serial 5A01B711(这个位置是设备识别号的后8位 )
    

伪装管理(RMS)注册:

cfgcli -s InternetGatewayDevice.X_CT-COM_UserInfo.Status 0
cfgcli -s InternetGatewayDevice.X_CT-COM_UserInfo.Result 1

开启 ipv6:

cfgcli -f -s InternetGatewayDevice.DeviceInfo.X_CT-COM_IPProtocolVersion.Mode 3

恢复出厂设置:

cfgcli -r

重启设备:

reboot

3. 注册(在恢复并重启后执行) #

插上光纤,找到光猫注册界面,输入LOID注册,大部分回到50%左右,不用管是否注册到100%

注册后运营商会随机超密,通过telnet来修改超密

telnet登录光猫后台,root密码是设置的aDm8H%MdA

  • telnet 192.168.1.1
  • su

修改超级登录密码:

cfgcli -s InternetGatewayDevice.DeviceInfo.X_CT-COM_TeleComAccount.Password aDm8H%MdA

返回光猫登录界面,用超级管理员账户登录:登录超级用户:CMCCAdmin,密码:aDm8H%MdA 找到新建internet选项,根据自己旧光猫信息进行新建internet连接,路由或者改桥接都行。

4. 收尾与故障排查 #

以上基本设置完就可以上网了。如果显示itms不在线,重新进telnet进行如下操作:

cfgcli -s InternetGatewayDevice.X_CT-COM_UserInfo.Status 0
cfgcli -s InternetGatewayDevice.X_CT-COM_UserInfo.Result 1

常用配置网页网址 #

  • 选省份界面:http://192.168.1.1/opid_setting.cgi
  • 固件升级路径:http://192.168.1.1/upgrade.cgi
  • 插件配置卸载路径:http://192.168.1.1/upgrade_plugin.cgi?
  • UPnP功能开启:http://192.168.1.1/upnp.cgi?
  • USB备份、恢复:http://192.168.1.1/usb.cgi?backup
  • TR069 RMS平台认证:http://192.168.1.1/tr69.cgi
  • AWIFI激活管理平台:http://192.168.1.1/awifi_config.cgi
  • 设备MAC等信息查看:http://192.168.1.1/bucpe.cgi
  • 设定password密码:http://192.168.1.1/gpon_config.cgi
  • 设定LAN端IPV6:http://192.168.1.1/lan_cu.cgi
  • 配置文件查看:http://192.168.1.1/dumpdatamodel.cgi

一个python脚本 #

众所周知,移动会随机超密,隔一段时间超密就会变,想改的话要在telnet里面改

于是,我开发了一个快速改超密的python脚本,推荐3.x版本的python

先安装一下telnetlib3 pip install telnetlib3

然后保存此文件为xxx.py,把用户密码填入

就可以双击运行了,不能的话把.py的默认应用改为python.exe

import asyncio
import telnetlib3
import sys
import time
import re

# Telnet 服务器信息
TELNET_HOST = "192.168.1.1"
TELNET_PORT = 23  # Telnet 默认端口
TELNET_USER = ""  # 光猫背后的普通用户
TELNET_PASS = ""  # 光猫背后的普通用户密码
SU_PASS = "aDm8H%MdA" # 你设置的root密码

# 要执行的命令
COMMANDS_AFTER_LOGIN = [
    "su",
    "cfgcli -s InternetGatewayDevice.DeviceInfo.X_CT-COM_TeleComAccount.Password aDm8H%MdA",
    "exit"
]

# 全局连接超时设置(应用于整个连接建立过程)
INITIAL_CONNECT_TIMEOUT = 10  # 秒


async def automate_telnet_with_su_async(host, port, user, password, su_password, commands):
    reader = None
    writer = None
    try:
        print(f"Connecting to Telnet host: {host}:{port} with timeout {INITIAL_CONNECT_TIMEOUT}s...")

        reader, writer = await asyncio.wait_for(
            telnetlib3.open_connection(host, port),
            timeout=INITIAL_CONNECT_TIMEOUT
        )

        # ====== 辅助函数:读取直到匹配 ======
        async def read_until_match(target_bytes_list, timeout=5, print_output=True):
            if not isinstance(target_bytes_list, list):
                target_bytes_list = [target_bytes_list]

            buffer = b""
            started_at = time.time()
            full_output_str = ""

            while time.time() - started_at < timeout:
                try:
                    chunk_str = await asyncio.wait_for(reader.read(4096), timeout=0.1)
                    if not chunk_str:
                        if buffer:
                            break
                        else:
                            raise ConnectionResetError("Connection closed while waiting for data.")

                    chunk_bytes = chunk_str.encode('ascii', errors='replace')
                    buffer += chunk_bytes
                    full_output_str += chunk_str

                    if print_output:
                        sys.stdout.write(chunk_str)
                        sys.stdout.flush()

                    for target_bytes in target_bytes_list:
                        if target_bytes in buffer:
                            return full_output_str
                except asyncio.TimeoutError:
                    continue
                except ConnectionResetError as e:
                    raise e

            target_str_repr = ", ".join([repr(t.decode('ascii', errors='ignore')) for t in target_bytes_list])
            raise asyncio.TimeoutError(f"Timeout waiting for any of {target_str_repr}.")

        # ====== Step 1: 登录 ======
        print("Waiting for login prompt...")
        output = await read_until_match([b"Login:", b"Username:"], timeout=7)
        if not re.search(r"Login:|Username:", output):
            raise Exception("Did not receive expected login prompt.")

        print(f"Sending username: {user}")
        writer.write(user + "\n")
        await writer.drain()
        await asyncio.sleep(0.5)

        print("Waiting for password prompt...")
        output = await read_until_match(b"Password:", timeout=5)
        if "Password:" not in output:
            raise Exception("Did not receive expected password prompt.")

        print(f"Sending password...")
        writer.write(password + "\n")
        await writer.drain()
        await asyncio.sleep(1.5)

        # ====== Step 2: 登录成功后,处理初始提示符 ($) ======
        print("Checking for initial prompt ($)...")
        current_prompt = None

        try:
            initial_data_str = await asyncio.wait_for(reader.read(65535), timeout=2)
            sys.stdout.write(initial_data_str)
            sys.stdout.flush()

            full_post_login_output = initial_data_str

            prompt_regex_dollar = re.compile(r'(?m)^.*?\$[\s\r\n]*$')
            prompt_regex_hash = re.compile(r'(?m)^.*?\#[\s\r\n]*$')

            last_line_stripped = full_post_login_output.strip().splitlines()[
                -1].strip() if full_post_login_output.strip() else ""

            if last_line_stripped.endswith("$"):
                current_prompt = "$"
            elif last_line_stripped.endswith("#"):
                current_prompt = "#"
            elif prompt_regex_dollar.search(full_post_login_output):
                current_prompt = "$"
            elif prompt_regex_hash.search(full_post_login_output):
                current_prompt = "#"

        except asyncio.TimeoutError:
            pass  # No significant initial output after login, or output didn't end with a clear prompt. This is handled by subsequent checks.

        if current_prompt is None:
            # print("No clear prompt. Sending an empty line to trigger it...") # Debug line removed
            writer.write("\n")
            await writer.drain()
            await asyncio.sleep(0.5)
            try:
                retry_output = await asyncio.wait_for(reader.read(1024), timeout=1)
                sys.stdout.write(retry_output)
                sys.stdout.flush()

                last_line_stripped = retry_output.strip().splitlines()[-1].strip() if retry_output.strip() else ""

                if last_line_stripped.endswith("$"):
                    current_prompt = "$"
                elif last_line_stripped.endswith("#"):
                    current_prompt = "#"
                elif prompt_regex_dollar.search(retry_output):
                    current_prompt = "$"
                elif prompt_regex_hash.search(retry_output):
                    current_prompt = "#"

            except asyncio.TimeoutError:
                pass  # Still no clear prompt after sending empty line. This will result in an exception below if current_prompt is still None.

        if current_prompt is None:
            raise Exception("Did not receive expected initial prompt ($ or #).")

        print(f"Connected. Current prompt: {current_prompt}")

        # ====== Step 3: 执行命令,包括 su 和后续命令 ======
        for cmd_index, cmd in enumerate(commands):
            print(f"Executing command: '{cmd}'")
            writer.write(cmd + "\n")
            await writer.drain()
            await asyncio.sleep(0.5)

            prompt_regex_dollar = re.compile(r'(?m)^.*?\$[\s\r\n]*$')
            prompt_regex_hash = re.compile(r'(?m)^.*?\#[\s\r\n]*$')

            if cmd == "su" and current_prompt == "$":
                print("Waiting for 'su' password prompt...")
                output = await read_until_match(b"Password:", timeout=5)
                if "Password:" not in output:
                    raise Exception("Did not receive 'su' password prompt for su.")

                print("Sending 'su' password...")
                writer.write(su_password + "\n")
                await writer.drain()
                await asyncio.sleep(1)

                print("Verifying prompt changed to #...")
                output = await read_until_match([b"\n# ", b" # ", b"\n#"], timeout=5)
                if not (output.strip().endswith("#") or prompt_regex_hash.search(output)):
                    raise Exception("Failed to switch to root (prompt is not '#').")
                current_prompt = "#"
                print("Successfully switched to root mode.")
            elif cmd == "exit" and current_prompt == "#":
                print("Exiting root mode. Checking for $ prompt or login prompt...")
                await asyncio.sleep(0.5)
                try:
                    output = await read_until_match([b"\n$ ", b" $ ", b"\n$", b"Login:", b"Username:"], timeout=7)
                    if output.strip().endswith("$") or prompt_regex_dollar.search(output):
                        current_prompt = "$"
                        print("Returned to user mode ($).")
                    elif re.search(r"Login:|Username:", output):
                        print("Exited to login prompt after 'exit' from root.")
                        break
                    else:
                        print(
                            f"Info: Did not strictly return to '$' prompt after exit from '#'.")  # Changed from Warning to Info
                except asyncio.TimeoutError:
                    print(
                        f"Info: Timeout waiting for '$' or login prompt after exit from '#'.")  # Changed from Warning to Info
                    try:  # Re-check
                        final_check_output = await asyncio.wait_for(reader.read(1024), timeout=1)
                        sys.stdout.write(final_check_output)
                        sys.stdout.flush()
                        if final_check_output.strip().endswith("$") or prompt_regex_dollar.search(final_check_output):
                            current_prompt = "$"
                            print("Returned to user mode ($) after re-check.")
                        elif re.search(r"Login:|Username:", final_check_output):
                            print("Exited to login prompt after 'exit' from root (re-check).")
                            break
                        else:
                            print(f"Info: Still no '$' or login prompt after re-check.")  # Changed from Warning to Info
                    except asyncio.TimeoutError:
                        pass  # Still no output after re-check after 'exit'.
            else:
                current_target_patterns = []
                if current_prompt == "$":
                    current_target_patterns = [b"\n$ ", b" $ ", b"\n$"]
                else:  # current_prompt == "#"
                    current_target_patterns = [b"\n# ", b" # ", b"\n#"]

                try:
                    output = await read_until_match(current_target_patterns, timeout=5)
                    is_prompt_matched = False
                    if current_prompt == "$" and (output.strip().endswith("$") or prompt_regex_dollar.search(output)):
                        is_prompt_matched = True
                    elif current_prompt == "#" and (output.strip().endswith("#") or prompt_regex_hash.search(output)):
                        is_prompt_matched = True

                    if not is_prompt_matched:
                        print(
                            f"Info: Expected '{current_prompt}' prompt after command '{cmd}', but did not find it clearly. Output: {output!r}")  # Changed from Warning to Info
                except asyncio.TimeoutError:
                    print(
                        f"Info: Timeout waiting for '{current_prompt}' prompt after command '{cmd}'.")  # Changed from Warning to Info

        # ====== Step 4: 关闭会话 ======
        print("Ensuring final exit from Telnet session...")
        writer.write("exit\n")
        await writer.drain()
        await asyncio.sleep(1)

        print("Reading final output before closing connection...")
        try:
            while True:
                data = await asyncio.wait_for(reader.read(1024), timeout=0.1)
                if not data:
                    break
                sys.stdout.write(data)
                sys.stdout.flush()
        except asyncio.TimeoutError:
            pass
        except ConnectionResetError:
            print("Connection was reset while reading final output.")

        print("\nTelnet session completed.")

    except asyncio.TimeoutError as e:
        print(f"\nError: Operation timed out - {e}")
    except ConnectionRefusedError:
        print(f"\nError: Connection refused to {host}:{port}. Is the device reachable and Telnet enabled?")
    except ConnectionResetError as e:
        print(f"\nError: Connection was reset by peer - {e}")
    except Exception as e:
        import traceback
        traceback.print_exc()
        print(f"\nError during Telnet automation: {e}")
    finally:
        if writer:
            # print("Closing Telnet connection...") # Debug line removed
            try:
                writer.close()
            except Exception:  # Don't print error for closing, unless it's critical. It might already be closed by peer.
                pass
                # print("Telnet connection definitively closed.") # Debug line removed


if __name__ == "__main__":
    asyncio.run(automate_telnet_with_su_async(TELNET_HOST, TELNET_PORT, TELNET_USER, TELNET_PASS, SU_PASS,
                                              COMMANDS_AFTER_LOGIN))

os.system("pause")

链接 #

https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=8417275 https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=8436100 https://www.right.com.cn/forum/thread-8403033-1-1.html


之前一个n1盒子砖了,不过还是想折腾,第一次玩光猫,走了很多弯路,好在猫到的第2天就配置好了。好玩爱玩