这篇文章,聊聊前一阵折腾小米路由器 BE3600 Pro 的一些事情,包括初步分析整套软硬件,以及使用 Docker 快速运行 Alist 这类好用,但体积较大的容器应用。
写在前面
我是小米路由器的相对早期用户,线上线下买过很多台小米路由器,线上能够翻到的订单记录,最早的一台是 2015 年的小米 Mini 路由器。
随后,陆陆续续的买过许多款不同的小米路由器,其中有很多经典款:青春版、R3G、AC2100、AX1800、4A,最近一台是小米的 BE6500 Pro。目前,家里还在使用的小米路由器是 2023 年双十一前购入的 BE6500 Pro,搭配之前购入的米家中枢网关,专门提供各种智能家居设备进行联网和管理使用。
3月初的时候,再次收到了“知乎来信”,这次能够不给厂商面子,随便折腾和吐槽的设备是我入手的 “BE6500 Pro 的青春版”:BE3600 Pro。
相比较之前的路由器,尤其是同系列的 BE6500 Pro,这台路由器单个尺寸会看起来稍小一些(矮胖一些),整体造型比较致敬十年前的经典款 R1D(只是没有硬盘)。
因为我家里已经有管理智能家居 IoT 设备的路由器(BE6500 Pro),所以在我拿到这台设备后的第一想法,并不是测试和折腾它的智能家居的功能,而是把想试试把它作为一个轻量服务器使用。
毕竟小米整套智能家居想更换网关,需要集体先解绑,再重新绑定,是一个巨大的工程(实在是太多体力活了)。这个经验是从之前的教训中得来的:家里原本用的小米 BE6500 Pro 经常出现断流问题,为了不影响正常上网体验,所以我不得不单独将小米路由器和本地网关重新组网,把所有智能家居设备都迁移到专用网络上,把智能家居和生活网络区分开来。希望后续米家的产品经理能够改进这个糟糕的体验,并且给想要帮助探索路由器问题的用户一个调试模式。
在这次折腾 BE3600 Pro 的时候,我在网上搜索了一圈,在一些视频博主的评论区中看到了一些类似 BE6500 Pro 的断流反馈,虽然购物平台基本上都会换货协助解决问题,但我觉得有限的折腾时间,应该花在刀刃上。
所以,当看着这款颜值在线、很像当年米家第一代带硬盘的R1D(路由轻NAS)的盒子组合时,我觉得用它来打造迷你服务器可能会很有趣:它原生支持Docker,性能不错又省电,特别是当它关掉作为路由器最耗性能的无线功能后,应该能发挥出更好的功耗表现。
准备工作
想要拿这个设备当轻量服务器使用,第一件事是获取设备的硬件信息和了解有哪些合适的 Linux 操作系统。
官方路由器的参数页里,没有体现使用的 SoC 的硬件参数。不过,还可以通过两个方式来获取信息:
- 第一种是拆机,对照芯片丝印来确认硬件信息。
- 第二种是使用网上公开的方法,敲开路由器软件的 SSH 服务的门,在路由设备它的操作系统中获取到想要的各种信息。
虽然我最后会拆掉这台设备,但是现在我选择第二种方法,主要因为需要对这台设备进行资料备份,以便出现极端情况下,能够有机会救活这套设备。并且,如果想要这台设备运行一些其他的系统,也需要更多的有效信息,而不仅仅是一个“芯片 ID 名称”。
强制设备初始化
两台路由器看起来外观一致,但其实设备是分主路由和子路由的。因为主路由的配置更好,所以操作一律先从主路由开始折腾。
为了确保设备环境可以复现,在开始折腾设备之前,我为设备做了强制恢复出厂设置:长按设备后部网线接口上的“重置键”,然后插上电源,等待设备橙灯快速闪烁,直至灯熄灭后,重新插上连接网络的网线和连接笔记本的网线,以及电源,耐心等待 LED 灯又长亮橙色变为漂亮的青色。
设备“越狱”:解开 SSH 权限
为了更方便后续的操作,当设备初始化之后,需要对设备进行简单的初始化。
特别提醒,本文使用的路由固件是 1.0.56
,如果你使用了更高版本的固件,无法复现,尝试回滚到这个版本即可。
验证设备可访问
通过在浏览器里访问 192.168.31.1
或使用 curl
先来判断设备是否连接正常,并处于就绪状态。
curl 192.168.31.1 -v
* Trying 192.168.31.1:80...
* Connected to 192.168.31.1 (192.168.31.1) port 80
> GET / HTTP/1.1
> Host: 192.168.31.1
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx
< Date: Wed, 26 Mar 2025 11:49:36 GMT
< Content-Type: text/html; charset=UTF-8
< Content-Length: 1770
< Last-Modified: Tue, 26 Nov 2024 02:21:15 GMT
< Connection: keep-alive
< ETag: "6745309b-6ea"
< Expires: Thu, 01 Jan 1970 00:00:01 GMT
< Cache-Control: no-cache
< X-Frame-Options: sameorigin
< Accept-Ranges: bytes
<
当 curl
命令执行完毕之后,除了 “200 OK” 之外,还能够看到小米路由器的 HTML 页面信息。
<!DOCTYPE html>
<!--[if lt IE 7]><html class="ie6 oldie" lang="zh"><![endif]-->
<!--[if IE 7]><html class="ie7 oldie" lang="zh"><![endif]-->
<!--[if IE 8]><html class="ie8 oldie" lang="zh"><![endif]-->
<!--[if gt IE 8]><!--> <html lang="zh"> <!--<![endif]-->
<head>
<meta http-equiv="x-ua-compatible" content="IE=9" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>小米路由器</title>
...
构建工具镜像
有网友将小米的越狱工具进行了开源,为了不影响本地的环境,并且能够进行更简单的复现,可以编写一个 Dockerfile 来构建一个工具镜像:
FROM python:3.10-slim
RUN sed -i 's#http://deb.debian.org#https://mirrors.tuna.tsinghua.edu.cn#g' /etc/apt/sources.list.d/debian.sources && \
apt-get update && apt-get install git -y && \
rm -rf /var/lib/apt/lists/*
# https://github.com/openwrt-xiaomi/xmir-patcher
RUN git clone https://github.com/openwrt-xiaomi/xmir-patcher.git /app/xmir-patcher
WORKDIR /app/xmir-patcher
RUN git checkout 5e3bc719deab2db364098ed83affa33c5d3b73bd
RUN python -m pip install -r requirements.txt
ENV PYTHONUNBUFFERED=TRUE
CMD ["python3", "menu.py"]
将上面的内容保存为 Dockerfile
后,使用 docker build -t xiaomi-patcher .
,可以完成镜像的构建:
# docker build -t xiaomi-patcher .
[+] Building 0.0s (10/10) FINISHED docker:desktop-linux
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 562B 0.0s
=> [internal] load metadata for docker.io/library/python:3.10-slim 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/6] FROM docker.io/library/python:3.10-slim 0.0s
=> CACHED [2/6] RUN sed -i 's#http://deb.debian.org#https://mirrors.tuna.tsinghua.edu.cn#g' /etc/apt/sources.list.d/debian.sources && 0.0s
=> CACHED [3/6] RUN git clone https://github.com/openwrt-xiaomi/xmir-patcher.git /app/xmir-patcher 0.0s
=> CACHED [4/6] WORKDIR /app/xmir-patcher 0.0s
=> CACHED [5/6] RUN git checkout 5e3bc719deab2db364098ed83affa33c5d3b73bd 0.0s
=> CACHED [6/6] RUN python -m pip install -r requirements.txt 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:ff897f8ca1fbc59b9c986aff2cbee7ed83ff3619f26e0642ed7113f5fcdd3757 0.0s
=> => naming to docker.io/library/xiaomi-patcher 0.0s
在完成镜像构建后,执行 docker run
命令,并将本地目录的 backup
目录映射到容器中的 /app/xmir-patcher/backups
目录中:
# docker run --rm -it -v `pwd`/backup:/app/xmir-patcher/backups xiaomi-patcher
==========================================================
Xiaomi MiR Patcher
1 - Set IP-address (current value: 192.168.31.1)
2 - Connect to device (install exploit)
3 - Read full device info
4 - Create full backup
5 - Install EN/RU languages
6 - Install Breed bootloader
7 - Install firmware (from directory "firmware")
8 - {{{ Other functions }}}
9 - [[ Reboot device ]]
0 - Exit
Select:
顺利的话,将能够看到上面的文字界面,提醒可以输入不同的数字,来完成对应的操作。
解开设备的 SSH 访问权限
输入 “2”,并敲下回车进行确认,很快就能够看到设备的 SSH 服务被启动的信息啦:
# Select: 2
device_name = RN04
rom_version = 1.0.56 release
mac_address = 00:e0:4c:xx:xx:xx
CountryCode = CN
Enter device WEB password: soulteary
Exploit "start_binding" detected!
Run SSH server on port 22 ...
#### SSH server are activated! ####
获取设备基础信息
在解除 SSH 权限后,可以先进行基础信息的获取和原始数据备份。输入“3”,并敲下回车后,程序会尝试进行设备各种信息的获取:
# Select: 3
Detect valid SSH server on port 22 (auth OK)
Download file: "/tmp/dmesg.log" ....
Download file: "/tmp/mtd_list.txt" ....
Download file: "/tmp/mtd_info.txt" ....
Download file: "/tmp/mtd_fdt.txt" ....
...
设备分区表信息
为了更好的使用这台设备,或许需要耐心从路由的固件处,开始了解这台路由,以及官方开发团队的一些设计。
个人认为,作为一台路由器来说,它的设备分区表算是比较复杂的了,足足有 35 项内容:
MTD partitions:
0 > addr: 0x00000000 size: 0x00180000 ro:0 name: "0:SBL1"
1 > addr: 0x00180000 size: 0x00180000 ro:0 name: "0:SBL1_1"
2 > addr: 0x00300000 size: 0x00100000 ro:0 name: "0:MIBIB"
3 > addr: 0x00400000 size: 0x00080000 ro:0 name: "0:BOOTCONFIG"
4 > addr: 0x00480000 size: 0x00080000 ro:0 name: "0:BOOTCONFIG1"
5 > addr: 0x00500000 size: 0x00380000 ro:0 name: "0:QSEE"
6 > addr: 0x00880000 size: 0x00380000 ro:0 name: "0:QSEE_1"
7 > addr: 0x00C00000 size: 0x00080000 ro:0 name: "0:DEVCFG"
8 > addr: 0x00C80000 size: 0x00080000 ro:0 name: "0:DEVCFG_1"
9 > addr: 0x00D00000 size: 0x00080000 ro:0 name: "0:TME"
10 > addr: 0x00D80000 size: 0x00080000 ro:0 name: "0:TME_1"
11 > addr: 0x00E00000 size: 0x00080000 ro:0 name: "0:CDT"
12 > addr: 0x00E80000 size: 0x00080000 ro:0 name: "0:CDT_1"
13 > addr: 0x00F00000 size: 0x00080000 ro:0 name: "0:APPSBLENV"
14 > addr: 0x00F80000 size: 0x00180000 ro:0 name: "0:APPSBL"
15 > addr: 0x01100000 size: 0x00180000 ro:0 name: "0:APPSBL_1"
16 > addr: 0x01280000 size: 0x00200000 ro:0 name: "0:ART"
17 > addr: 0x01480000 size: 0x00080000 ro:0 name: "0:TRAINING"
18 > addr: 0x01500000 size: 0x00040000 ro:0 name: "0:LICENSE"
19 > addr: 0x01540000 size: 0x02D00000 ro:0 name: "rootfs"
20 > addr: 0x04240000 size: 0x02D00000 ro:0 name: "rootfs_1"
21 > addr: 0x06F40000 size: 0x00080000 ro:0 name: "bdata"
22 > addr: 0x06FC0000 size: 0x00080000 ro:0 name: "crash"
23 > addr: 0x07040000 size: 0x02F40000 ro:0 name: "overlay"
24 > addr: 0x09F80000 size: 0x02000000 ro:0 name: "central"
25 > addr: 0x0BF80000 size: 0x04000000 ro:0 name: "docker"
26 > addr: 0x0FF80000 size: 0x00800000 ro:0 name: "app_data"
27 > addr: 0x10780000 size: 0x0F880000 ro:0 name: "other"
28 > addr: 0xFFFFFFFF size: 0x00363E16 ro:0 name: "kernel"
29 > addr: 0xFFFFFFFF size: 0x0175F000 ro:0 name: "ubi_rootfs"
30 > addr: 0xFFFFFFFF size: 0x00C1C000 ro:0 name: "cfg"
31 > addr: 0xFFFFFFFF size: 0x00C1C000 ro:0 name: "user"
32 > addr: 0xFFFFFFFF size: 0x00B62000 ro:0 name: "plugin"
33 > addr: 0xFFFFFFFF size: 0x033F3000 ro:0 name: "ubi_docker"
34 > addr: 0xFFFFFFFF size: 0x007A1000 ro:0 name: "ubi_central"
35 > addr: 0xFFFFFFFF size: 0x0EB68000 ro:0 name: "data"
上面获得的一些分区地址为 0xFFFFFFFF
,这些分区可能由 UBI 动态分配或程序逻辑映射,实际物理地址应该是在系统运行时确定,而非固定的物理地址。从命名和分区设置规律来看,分区后缀 _1
表示设备采用类似 Android 的冗余(双镜像)机制,便于在升级失败或损坏时自动回退到备份版本。
如果对上面的分区进行分类,大概可以得到三类功能。
Bootloader 和启动相关分区
- Secondary Boot Loader:
0:SBL1
和0:SBL1_1
,辅助引导加载程序,用于设备启动,存在两套说明路由使用了类似 Android 手机的 A/B 分区引导类似的设计。 - 多镜像启动信息块(Multi-Image Boot Information Block):
0:MIBIB
,记录镜像加载的配置信息。 - 启动配置区域:
0:BOOTCONFIG
和0:BOOTCONFIG1
,保存设备两种不同版本固件引导时使用的配置数据。 - Qualcomm 安全执行环境 (Qualcomm Secure Execution Environment):
0:QSEE
和0:QSEE_1
:,用于安全启动和安全计算。 - 设备配置:
0:DEVCFG
和0:DEVCFG_1
,存储设备硬件相关的配置信息。 - 可信管理引擎(Trusted Management Engine):
0:TME
和0:TME_1
,用于设备安全管理,估计是保存配对后的米家设备。 - 配置数据表(Configuration Data Table):
0:CDT
和0:CDT_1
,设备硬件配置参数。 - 应用引导加载程序环境:
0:APPSBLENV
,存储 U-Boot 或其他 Bootloader 环境变量。 - 路由器的 Bootloader(如 U-Boot):
0:APPSBL
和0:APPSBL_1
,用于加载内核。 - 无线射频校准数据分区:
0:ART
,存储无线芯片的校准数据。 - 可能是根据环境自适应学习的配置或程序数据:
0:TRAINING
。 - 相关开源、闭源项目的许可证信息:
0:LICENSE
。
系统和根文件系统相关分区:
- 存储主系统的根文件系统镜像:
rootfs
和rootfs_1
,类似 Android 的双镜像布局用于系统升级和回滚。 - Overlay 文件系统分区:
overlay
,存放设备运行过程中用户写入的修改和数据。 - 基于 UBI 格式的根文件系统分区:
ubi_rootfs
,设备实际启动时使用的根文件系统可能位于此处。 - 存储 Linux 内核镜像:
kernel
。
数据和应用相关分区:
- 设备特有标识信息(如 MAC 地址、序列号)或其他基础数据:
bdata
。 - 存储设备异常崩溃时的日志和调试信息:
crash
。 - 可能存储设备的核心应用或服务的数据:
central
。 - Docker 相关分区:
docker
和ubi_docker
,存储镜像或容器相关数据。 - 存储第三方应用、插件或相关配置信息:
app_data
和plugin
。 - 设备用户配置、个性化数据存储区域:
cfg
和user
。 - 基于 UBI 格式存储的设备核心服务(中枢网关)或应用数据:
ubi_central
。 - 不确定存储的内容:
other
。
设备内核信息
继续阅读程序获取的设备信息,可以获得非常多有趣的信息:
Kernel command line:
ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs cnss2.enable_mlo_support=1 rootwait clk_ignore_unused vmalloc=1G
RootFS info:
num = 0
mtd_num = None
mtd_dev = "None"
partition = "rootfs"
Base info:
Linux version: None
DISTRIB_TARGET = ipq53xx/ipq53xx_32
DISTRIB_ARCH = arm_cortex-a7_neon-vfpv4
CPU arch: armv7
CPU name: ipq53xx
Version info:
UBoot: None
OpenWrt: unknown
Firmware: 1.0.56
Channel: release
BuildTime: Tue, 26 Nov 2024 03:23:06 +0000
Hardware: RN04
UBoot(2): 1.0.2
ubi.mtd=rootfs
:说明使用 UBI(无排序块设备)机制,将名为 rootfs 的分区作为根文件系统。root=mtd:ubi_rootfs
:根文件系统位于名为ubi_rootfs
的MTD(Memory Technology Device)分区中。rootfstype=squashfs
:根文件系统采用 SquashFS 类型,这是一个只读、压缩的文件系统,常用于嵌入式设备。cnss2.enable_mlo_support=1
:启用了 Qualcomm Wi-Fi 芯片(CNSS2)的 MLO(Multi-Link Operation,多链路操作)功能。rootwait
:内核启动时会等待根文件系统设备准备好后再继续启动。clk_ignore_unused
:忽略未使用的时钟,避免某些时钟被关闭,从而确保系统稳定运行。vmalloc=1G
:预留1GB虚拟内存用于动态分配内存,通常用于加载较大模块或驱动。(这台设备支持 Docker,或许相关)ipq53xx
如果要自行构建系统,需要找到高通 IPQ53xx 芯片相关的资料。armv7
设备使用和支持 32 位的程序,构建程序的时候,需要指定 32 位程序相关参数。BuildTime: Tue, 26 Nov 2024 03:23:06 +0000
:我手头的这台设备的初始系统版本,构建于去年的 11 月 26 日。Hardware: RN04
,设备代号为 RN04,或许说明再次之前还有三个不同的方案。UBoot: 1.0.2
,使用的引导程序版本为 1.0.2,这至少是第二个小的修订版本。
NVRam 、Bootloader、ENV 信息
继续分析最后三项打印出来的设备信息,同样可以获得有趣的内容:
NVRam params:
flag_boot_rootfs=0
flag_boot_success=1
flag_boot_type=2
flag_last_success=0
flag_ota_reboot=0
flag_try_sys1_failed=0
flag_try_sys2_failed=0
ipaddr=192.168.31.1
serverip=192.168.31.100
Bootloader info:
Download file: "/tmp/bl_0SBL1.bin" ....
addr: 0x00000000 (size: 0x00180000)
image size: 12 bytes
type: None
Download file: "/tmp/bl_0APPSBL.bin" ....
addr: 0x00F80000 (size: 0x00180000)
image size: 177 bytes
type: None
ENV info:
Download file: "/tmp/env_0APPSBLENV.bin" ....
addr: 0x00F00000 (size: 0x00080000)
CRC32: 0x599E156B
max size: 0x10000
Download file: "/tmp/env_bdata.bin" ....
addr: 0x06F40000 (size: 0x00080000)
CRC32: 0x546267BE
max size: 0x10000
Download file: "/tmp/env_0SBL1.bin" ....
addr: 0x00060000 (size: 0x00120000) breed
NVRAM (Non-Volatile RAM) 标志类信息和网络参数
- 启动标志(flag)类参数:
flag_boot_rootfs=0
,当前使用根文件系统编号为0,表示设备启动时默认使用第一个根文件系统分区。 - 设备上一次启动是否正常:
flag_boot_success=1
,推测这里是 0 的时候,程序将调整上面的flag_boot_rootfs
为两个分区中的另外一个。 - 启动类型设定:
flag_boot_type=2
不太清楚这里的定义,这里的 2 代表正常启动或等待初始化都有可能。 - 上次正常启动分区号:
flag_last_success=0
,上一次成功启动的分区编号,这里表示上次启动的是系统的第一个分区。 - OTA 升级后是否需要重启:
flag_ota_reboot=0
,OTA(远程升级)后是否需要重启,当前 0 表示不需要。 - 两套系统是否启动失败:
flag_try_sys1_failed=0
应该表示两套系统都正常,均为出现启动失败。 ipaddr=192.168.31.1
,设备启动时的默认 IP 地址。serverip=192.168.31.100
,DHCP 开始提供服务的 IP 地址。
Bootloader信息
设备 Bootloader 镜像分区和镜像文件:
- 文件
/tmp/bl_0SBL1.bin
:地址 0x00000000,分区大小 0x00180000(1.5MB),得到的镜像大小仅 12 字节,有可能只存了某个数值或文件占位符。 - 文件
/tmp/bl_0APPSBL.bin
:地址 0x00F80000,分区大小 0x00180000(1.5MB),得到镜像大小 177 字节,和上面类似,并非包含完整的引导程序,大概率是占位文件。
环境变量(ENV)信息:
- 文件
/tmp/env_0APPSBLENV.bin
:地址 0x00F00000,分区大小 0x00080000(512KB),最大可用大小为 0x10000(64KB),存放Bootloader环境变量,比如启动参数等。 - 文件
/tmp/env_bdata.bin
:地址 0x06F40000,分区大小 0x00080000(512KB),最大可用大小同样为64KB,存放设备基础信息(如序列号、MAC地址、出厂信息等)。 - 文件
/tmp/env_0SBL1.bin
:地址 0x00060000,分区大小 0x00120000(约1.1MB),默认的注释为 breed,这说明路由器可能在使用 Breed 作为引导程序,或者魔改后兼容 Breed 的引导程序。
备份设备原始固件
输入 “4”,敲下回车,Docker 工具程序会将路由的原始固件备份到本地的 backup
目录中:
# Select: 4
Detect valid SSH server on port 22 (auth OK)
Download file: "/tmp/dmesg.log" ....
Download file: "/tmp/mtd_list.txt" ....
Download file: "/tmp/mtd_info.txt" ....
Download file: "/tmp/mtd_fdt.txt" ....
Download file: "/tmp/kcmdline.log" ....
Download file: "/tmp/kver.txt" ....
Download file: "/tmp/dmesg.log" ....
Download file: "/tmp/mtd_list.txt" ....
Download file: "/tmp/mtd_info.txt" ....
Download file: "/tmp/mtd_fdt.txt" ....
Full backup creating...
Download file "./backups/dump_mtd0_0.bin"...
File "backups/mtd0_0SBL1.bin" created!"
Backup of "0SBL1" saved to file "./backups/mtd0_0SBL1.bin"
Download file "./backups/dump_mtd1_0.bin"...
File "backups/mtd1_0SBL11.bin" created!"
Backup of "0SBL11" saved to file "./backups/mtd1_0SBL11.bin"
Download file "./backups/dump_mtd2_0.bin"...
File "backups/mtd2_0MIBIB.bin" created!"
Backup of "0MIBIB" saved to file "./backups/mtd2_0MIBIB.bin"
Download file "./backups/dump_mtd3_0.bin"...
File "backups/mtd3_0BOOTCONFIG.bin" created!"
Backup of "0BOOTCONFIG" saved to file "./backups/mtd3_0BOOTCONFIG.bin"
Download file "./backups/dump_mtd4_0.bin"...
...
耐心等待固件备份完毕,将得到一堆 bin
文件(未压缩时有 600MB+):
ls backup
mtd0_0SBL1.bin mtd15_0APPSBL1.bin mtd20_rootfs1.bin mtd26_appdata.bin mtd31_user.bin mtd4_0BOOTCONFIG1.bin
mtd10_0TME1.bin mtd16_0ART.bin mtd21_bdata.bin mtd27_other.bin mtd32_plugin.bin mtd5_0QSEE.bin
mtd11_0CDT.bin mtd17_0TRAINING.bin mtd22_crash.bin mtd28_kernel.bin mtd33_ubidocker.bin mtd6_0QSEE1.bin
mtd12_0CDT1.bin mtd18_0LICENSE.bin mtd23_overlay.bin mtd29_ubirootfs.bin mtd34_ubicentral.bin mtd7_0DEVCFG.bin
mtd13_0APPSBLENV.bin mtd19_rootfs.bin mtd24_central.bin mtd2_0MIBIB.bin mtd35_data.bin mtd8_0DEVCFG1.bin
mtd14_0APPSBL.bin mtd1_0SBL11.bin mtd25_docker.bin mtd30_cfg.bin mtd3_0BOOTCONFIG.bin mtd9_0TME.bin
将文件保存好,后面可以开始进一步的信息分析。
使用 SSH 命令连接设备
如果仔细翻阅上面 Docker 镜像工具中使用的开源 Python 项目,能够发现工具为了操作简单,会将 root 密码进行修改,改为相同的内容 root
字符串:
# change password for root
echo -e "root\nroot" | (passwd root)
所以,可以通过下面的命令,来快速连接设备:
# ssh root@192.168.31.1
The authenticity of host '192.168.31.1 (192.168.31.1)' can't be established.
RSA key fingerprint is SHA256:L23dIByGO5DsfaNxAHAzuSd0eBa9TilmhdMzY3qYh9o.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.31.1' (RSA) to the list of known hosts.
root@192.168.31.1's password:
BusyBox v1.36.1 (2024-11-26 02:21:15 UTC) built-in shell (ash)
-----------------------------------------------------
Welcome to XiaoQiang!
-----------------------------------------------------
$$$$$$\ $$$$$$$\ $$$$$$$$\ $$\ $$\ $$$$$$\ $$\ $$\
$$ __$$\ $$ __$$\ $$ _____| $$ | $$ | $$ __$$\ $$ | $$ |
$$ / $$ |$$ | $$ |$$ | $$ | $$ | $$ / $$ |$$ |$$ /
$$$$$$$$ |$$$$$$$ |$$$$$\ $$ | $$ | $$ | $$ |$$$$$ /
$$ __$$ |$$ __$$< $$ __| $$ | $$ | $$ | $$ |$$ $$<
$$ | $$ |$$ | $$ |$$ | $$ | $$ | $$ | $$ |$$ |\$$\
$$ | $$ |$$ | $$ |$$$$$$$$\ $$$$$$$$$ | $$$$$$ |$$ | \$$\
\__| \__|\__| \__|\________| \_________/ \______/ \__| \__|
root@XiaoQiang:~#
登录路由之后,能够看到巨大的 “ARE U OK” 艺术字,这个“习俗”在十年前的小米设备中就有了,算是一个约定俗成的无害的彩蛋吧。
获取设备硬件信息
在上文中从固件中静态分析的角度,了解了一些硬件相关的信息,现在再来根据系统动态运行的内容,补充获取一些基础信息吧:
root@XiaoQiang:~# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 66.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 1
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 66.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 2
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 66.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
processor : 3
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 66.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x51
CPU architecture: 7
CPU variant : 0xa
CPU part : 0x801
CPU revision : 4
Hardware : Generic DT based system
Revision : 0000
Serial : 0000000000000000
和之前分析的一致,设备使用的是一颗 ARMv7 Rev 4 的处理器,具备 4 个核心,Bogo MIPS 估算处理器速度为 66.00
。CPU 特性支持还挺多,包含了 neon
指令,这个指令可以快速处理视频或图片,做语音识别等等(不过这台路由器看起来默认没有这些功能)。同样支持 lpae
,能够支持 4GB 以上的内存,或许未来会有人魔改这台设备的内存,来让 Docker 运行一些吃资源的应用。
接下来,了解下内存相关的使用情况:
root@XiaoQiang:~# cat /proc/meminfo
MemTotal: 443036 kB
MemFree: 184668 kB
MemAvailable: 271344 kB
Buffers: 9620 kB
Cached: 112280 kB
SwapCached: 0 kB
Active: 90440 kB
Inactive: 52768 kB
Active(anon): 26956 kB
Inactive(anon): 1524 kB
Active(file): 63484 kB
Inactive(file): 51244 kB
Unevictable: 5008 kB
Mlocked: 0 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 443036 kB
LowFree: 184668 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 26316 kB
Mapped: 83488 kB
Shmem: 2164 kB
KReclaimable: 7492 kB
Slab: 62284 kB
SReclaimable: 7492 kB
SUnreclaim: 54792 kB
KernelStack: 2928 kB
PageTables: 1188 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 221516 kB
Committed_AS: 147256 kB
VmallocTotal: 1556480 kB
VmallocUsed: 22660 kB
VmallocChunk: 0 kB
Percpu: 1232 kB
设备整体装配了 512MB 的内存,因为预留了一部分给硬件共享使用,实际可用的内存是 432MB,默认情况下可用内存大约 265MB(271344KB),空闲内存 180MB(184668KB)。
在不运行 Docker 程序的情况下,内存资源是比较富裕的,放几年前应该是高端中的旗舰设备,不过这几年路由器蓬勃发展,这个配置大概是一个中上游水平吧。
也正是因为设备配备了比较大的内存,允许了即使不刷机为其他系统,也能够运行较大体积的容器应用程序。(下文展开)
文件系统相关信息
接下来,使用命令继续获取设备运行时的文件系统信息:
root@XiaoQiang:~# df -h
Filesystem Size Used Available Use% Mounted on
/dev/mtdblock29 23.3M 23.3M 0 100% /
tmpfs 216.3M 2.1M 214.2M 1% /tmp
ubi23:cfg 9.4M 3.1M 5.8M 34% /data
ubi23:user 9.4M 2.8M 6.1M 31% /data/usr
ubi23:plugin 8.7M 28.0K 8.2M 0% /data/userdisk
ubi23:plugin 8.7M 28.0K 8.2M 0% /userdisk
/dev/mtdblock29 23.3M 23.3M 0 100% /userdisk/data
/dev/ubiblock25_0 51.9M 51.9M 0 100% /data/docker
/dev/ubiblock24_0 7.6M 7.6M 0 100% /data/central
ubi27_0 215.6M 17.9M 193.0M 8% /data/other_vol
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /tmp/sec_cfg/etc
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /data/etc
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/config
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/datacenterconfig
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/smartcontroller
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/parentalctl
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/smartvpn
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/ppp
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/crontabs
/dev/mapper/sec_cfg 5.7M 975.0K 4.3M 18% /etc/mipctl
/dev/mapper/other_enc
177.5M 268.0K 164.0M 0% /data/other
tmpfs 512.0K 0 512.0K 0% /dev
/dev/mapper/other_enc
177.5M 268.0K 164.0M 0% /data/other/docker
能够看到整个小米路由的固件其实只有 23.3MB (/dev/mtdblock29
),临时文件系统 tmpfs(/tmp
)划分了 216.3MB 的内存,目前使用了 2.1M(1%)。用户数据配置(/data
)存储配置(ubi23:cfg
)和用户数据(ubi23:user
)分别使用了 9.4M 空间,ubi23:plugin
插件分区配置了 8.7MB。
Docker 分区(/dev/ubiblock25_0
)使用了 51.9M的空间,核心应用中枢网关的镜像分区(/dev/ubiblock24_0
),占用了 7.6M 的空间。剩下的其他数据目录(ubi27_0
)可用空间为 215.6M。固件本身还支持了一些用于安全加密配置信息保存的分区。
整体设计上来看非常合理,本体固件是和多数路由设备一样的 SquashFS 只读分区。单独使用 cfg
和 user
分区将配置数据和用户数据分离,便于系统升级、备份和初始化还原。原生支持使用 Docker 应用,同时特别做了专门的加密映射,用来增强数据安全。
无线相关信息
虽然我不计划用这台设备做无线路由器使用,但是还是通过命令简单查看了设备无线相关信息:
root@XiaoQiang:~# iwconfig
wifi0 no wireless extensions.
br-docker no wireless extensions.
eth0.3 no wireless extensions.
bhap_mld0 IEEE 802.11 Mode:Master
RTS thr:off Fragment thr:off
Power Management:off
wl5 IEEE 802.11bea ESSID:"MiMesh_123123"
Mode:Master Frequency:5.24 GHz Access Point: Not-Associated
Bit Rate:0 kb/s Tx-Power=28 dBm
RTS thr:off Fragment thr:off
Encryption key:1234-1122-1234-1122-1234-1122-1234-1122 Security mode:restricted
Power Management:off
Link Quality=0/94 Signal level=-96 dBm Noise level=-96 dBm (BDF averaged NF value in dBm)
Rx invalid nwid:178 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
gretap0 no wireless extensions.
eth0 no wireless extensions.
gre0 no wireless extensions.
ip6tnl0 no wireless extensions.
eth1 no wireless extensions.
soc1 no wireless extensions.
wl0 IEEE 802.11bea ESSID:"Xiaomi_TEST"
Mode:Master Frequency:5.24 GHz Access Point: 90:FB:5D:70:E5:95
Bit Rate:2.8824 Gb/s Tx-Power=28 dBm
RTS thr:off Fragment thr:off
Encryption key:1234-1122-1234-1122-1234-1122-1234-1122 Security mode:restricted
Power Management:off
Link Quality=0/94 Signal level=-96 dBm Noise level=-96 dBm (BDF averaged NF value in dBm)
Rx invalid nwid:1543 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
wl1 IEEE 802.11beg ESSID:"Xiaomi_TEST"
Mode:Master Frequency:2.437 GHz Access Point: 90:FB:5D:70:E5:94
Bit Rate:344.2 Mb/s Tx-Power=28 dBm
RTS thr:off Fragment thr:off
Encryption key:1234-1122-1234-1122-1234-1122-1234-1122 Security mode:restricted
Power Management:off
Link Quality=0/94 Signal level=-96 dBm Noise level=-96 dBm (BDF averaged NF value in dBm)
Rx invalid nwid:1813 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
mld-wifi0 IEEE 802.11 Mode:Master
RTS thr:off Fragment thr:off
Power Management:off
br-lan no wireless extensions.
wifi1 no wireless extensions.
erspan0 no wireless extensions.
br-miot no wireless extensions.
eth0.2 no wireless extensions.
bhsta_mld0 IEEE 802.11 ESSID:off/any
Mode:Managed Access Point: Not-Associated
RTS thr:off Fragment thr:off
Encryption key:off
Power Management:off
eth0.1 no wireless extensions.
lo no wireless extensions.
bond0 no wireless extensions.
wl4 IEEE 802.11beg ESSID:"MiMesh_123123123"
Mode:Master Frequency:2.437 GHz Access Point: Not-Associated
Bit Rate:0 kb/s Tx-Power=28 dBm
RTS thr:off Fragment thr:off
Encryption key:1234-1122-1234-1122-1234-1122-1234-1122 Security mode:restricted
Power Management:off
Link Quality=0/94 Signal level=-96 dBm Noise level=-96 dBm (BDF averaged NF value in dBm)
Rx invalid nwid:178 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
hostap_mld0 IEEE 802.11 Mode:Master
RTS thr:off Fragment thr:off
Power Management:off
wl13 IEEE 802.11beg ESSID:"123123123123123_miwifi"
Mode:Master Frequency:2.437 GHz Access Point: Not-Associated
Bit Rate:0 kb/s Tx-Power=28 dBm
RTS thr:off Fragment thr:off
Encryption key:off
Power Management:off
Link Quality=0/94 Signal level=-96 dBm Noise level=-96 dBm (BDF averaged NF value in dBm)
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:0
soc0 no wireless extensions.
从打印出的日志来看,设备是支持 Wi-Fi 7 的(IEEE 802.11bea),当前空载时的系统速率为 2.8824 Gb/s
(并且是 28 dBm 的较高功率)。同时还支持两个不同频率的小米 Mesh 无线接口(2.4GHz 和 5GHz),以及还有几个感觉是用于不同模式的接口,从命名推测是无线回程(Backhaul),多路复用(MLO)接口,以及可能用于米家设备漫游发现的接口等,具体需要有场景的同学实测了。
OpenWRT 相关信息
在系统的 /etc
分区里,能够看到有两个名为 openwrt
前缀的文件:
# ls /etc/openwrt_*
/etc/openwrt_release /etc/openwrt_version
阅读文件内容,能够发现当前镜像是基于 18.04 这个比较古老的版本构建的:
# cat /etc/openwrt_*
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='18.06-SNAPSHOT'
DISTRIB_REVISION='unknown'
DISTRIB_TARGET='ipq53xx/ipq53xx_32'
DISTRIB_ARCH='arm_cortex-a7_neon-vfpv4'
DISTRIB_DESCRIPTION='OpenWrt 18.06-SNAPSHOT unknown'
DISTRIB_TAINTS='no-all busybox override'
unknown
如果想要构建一些 OpenWRT 插件在这台设备上使用,或许需要使用旧版本 OpenWRT 相关的代码或工具。
使用 uname -a
得到的内核参数,进一步能够确定上面的判断:
Linux XiaoQiang 5.4.213 #0 SMP PREEMPT Tue Nov 26 02:21:15 2024 armv7l GNU/Linux
OpenWRT 18.06 默认的内核应该是 4.4 / 4.19,而小米使用的是 5.4 内核,说明路由器团队应该打了大量补丁。不同版本的 OpenWRT 的内核接口、系统 C 库、ABI 差异、库依赖接口差异都可能会浪费大量时间。
当然,也可以选择构建一个新的适配于这套硬件的新固件系统(放弃可能最佳的无线性能,而专注获取新的 Linux 特性和可能的更高的计算效率)。
Docker 相关信息
当完成初始化之后,Docker 也会随设备启动:
# ps | grep docker
4840 root 1336 S grep docker
18629 root 804m S /data/docker/dockerd --config-file=/tmp/dockerd/daemon.json
18691 root 689m S containerd --config /tmp/docker_exec/containerd/containerd.toml --log-level warn
通过 docker info
,能够看到小米路由器使用的 Docker 版本还蛮新的:
root@XiaoQiang:~# docker info
Client:
Version: 26.1.2
Context: default
Debug Mode: false
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 26.1.2
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 926c9586fe4a6236699318391cd44976a98e31f1
runc version: v1.1.12-0-g51d5e94
init version: de40ad0
Kernel Version: 5.4.213
Operating System: OpenWrt 18.06-SNAPSHOT
OSType: linux
Architecture: armv7l
CPUs: 4
Total Memory: 432.7MiB
Name: XiaoQiang
ID: 021888d8-fa5f-4f1d-b750-49d402cafab7
Docker Root Dir: /data/other/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine
WARNING: No swap limit support
WARNING: No blkio throttle.read_bps_device support
WARNING: No blkio throttle.write_bps_device support
WARNING: No blkio throttle.read_iops_device support
WARNING: No blkio throttle.write_iops_device support
root@XiaoQiang:~#
不过,默认情况下只是 Docker 服务启动了,并没有运行任何容器,也没有导入任何 Docker 镜像。
这里先不研究如何使用小米固件中默认自带的中枢网关,而是来尝试让小米路由器能够通过 Docker,从私有化的 Docker 仓库中下载应用并进行快速启动。
支持使用私有容器仓库
默认情况下,容器仓库都是使用 HTTPS 协议进行交互。如果内网中的容器仓库使用的是自签名证书,在获取镜像的时候,将得到类似下面的错误信息:
# docker pull docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
Error response from daemon: Get "https://docker.mongo.lab.com/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority
想要在小米路由器中解决这个问题,需要在官方提供的 /etc/init.d/mi_docker
Docker 管理脚本中,添加一些内容,让路由器的 Docker 程序在初始化的时候,能够允许访问不被信任的证书环境。(更好的方式是配置容器信任证书,但在路由器环境中,除非构建固件,否则配置非常麻烦)
使用路由器自带的 VIM 编辑器,对程序进行修改 vim /etc/init.d/mi_docker
,找到配置中的:
json_add_string "data-root" "${data_root}"
json_add_string "log-level" "${log_level}"
在上面添加:
json_add_array "insecure-registries"
json_add_string "" "docker.mongo.lab.com"
json_close_array
使用 :wq
保存文件后,执行 /etc/init.d/mi_docker restart
重启容器服务,再次使用 docker pull
命令下载容器,会发现已经可以正常访问仓库,但是缺少鉴权信息:
# docker pull docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
Error response from daemon: Head "https://docker.mongo.lab.com/v2/xhofe/alist/manifests/v3.43.0-aria2": no basic auth credentials
如果使用 docker login
直接登录仓库,会发现因为路由器的只读分区机制,登录操作无法实现:
# docker login docker.mongo.lab.com
Username: soulteary
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Error saving credentials: mkdir /root/.docker: read-only file system
解决的方法也比较简单,可以在临时目录中创建一个 .docker
目录,在登录的时候,指定容器要使用的配置目录即可完成仓库鉴权:
# mkdir -p /tmp/.docker
# docker --config /tmp/.docker login docker.mongo.lab.com
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /tmp/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
再次使用 docker pull
下载镜像的时候,可以通过添加 --config
参数,指定刚刚的鉴权信息,来进行仓库中的镜像下载:
# docker --config /tmp/.docker pull docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
v3.43.0-aria2: Pulling from xhofe/alist
56c91669ab0b: Pull complete
86fc7f545902: Pull complete
52b30c650f97: Pull complete
2298c9ed7e57: Pull complete
55e8e23d687c: Pull complete
d3c7863c3dba: Extracting [==================================================>] 30.16MB/30.16MB
failed to register layer: write /opt/alist/alist: no space left on device
不过,路由器上目前的磁盘空间并不够大,不能够将 Alist 镜像下载下来。所以还需要调整下之前的 /etc/init.d/mi_docker
程序,将 Docker 数据目录调整到一个可以放下 Alist 容器的地方。原始的数据保存目录是:
json_add_string "data-root" "${data_root}"
可以将这个地址调整为大量冗余资源的,基于内存的临时目录中:
json_add_string "data-root" "/tmp/datadir"
和上文一样,重启 Docker 服务后,再次执行容器镜像下载命令:
# docker --config /tmp/.docker pull docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
v3.43.0-aria2: Pulling from xhofe/alist
56c91669ab0b: Pull complete
86fc7f545902: Pull complete
52b30c650f97: Pull complete
2298c9ed7e57: Pull complete
55e8e23d687c: Pull complete
d3c7863c3dba: Pull complete
Digest: sha256:018b25d02849a717f6d5a8903b6fcb42ea5a9137a927c1991c66656f0fced671
Status: Downloaded newer image for docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
稍等片刻,Alist 这个 100 多MB 的镜像就能够被正常下载到路由器上啦。
在小米路由器上快速运行 Alist
完成了镜像的下载后,对 Alist 说明文档中的命令,稍加调整,直接运行:
# docker run -d --restart=always -v /tmp/alist:/opt/alist/data -p 5244:5244 -e PUID=0 -e PGID=0 -e UMASK=022 --name="alist" docker.mongo.lab.com/xhofe/alist:v3.43.0-aria2
707333a7d6a4afcad06cc85dc52eb26b5501e4e1ec60e9e11e0cf01edb0eafe
当 Alist 运行完毕之后,我们就能够通过访问 http://192.168.31.1:5244
来访问 Alist 的界面啦。
为了能够登录 Alist,我们需要手动设置下程序的管理员密码:
docker exec -it alist ./alist admin set soulteary
命令执行完毕,会显示密码已经被设置为上面命令中的 soulteary
。
INFO[2025-03-26 16:20:42] reading config file: data/config.json
INFO[2025-03-26 16:20:42] load config from env with prefix: ALIST_
INFO[2025-03-26 16:20:42] init logrus...
INFO[2025-03-26 16:20:42] admin user has been updated:
INFO[2025-03-26 16:20:42] username: admin
INFO[2025-03-26 16:20:42] password: soulteary
使用我们修改后的密码和 admin
用户名就能够完成系统的登录了:
剩下的事情就是在 Alist 的管理后台里,配置你的数据源,就能够通过小米路由器,来浏览或播放你收藏的各种云资源啦。
最后
这个月比较忙,这篇文章原计划在月初发布,没曾想到拖到了月底。希望上面的内容,对于想折腾这台配置还不错的路由器的你有帮助。
–EOF