普通视图

发现新文章,点击刷新页面。
昨天以前首页

Proxmox VE 部署 OpenWrt 实现旁路由图文说明教程

2025年12月15日 08:30

Proxmox VE 部署 OpenWrt 实现旁路由图文说明教程

系列文章:家庭服务器

前几天打算把家里小主机的服务升级一下!因为更新过程中需要访问Github等海外线上服务。但是!你懂的,经常莫名其妙无法访问!升级中断后导致源码出现了问题!

虽然博主之前分享过很多解决方案:GitHub国内加速,但在Linux上使用还是不太方便!

于是周末折腾了一下利用 Proxmox 安装OpenWrt,然后OpenWrt旁路由为其他内网服务器加速!

更多内容:家庭IDC / Proxmox

 

 

OpenWrt选择

  •  Lean 的 OpenWrt 源码(Lienol)

该源码库在 OpenWrt 社区影响力巨大,但其主仓库地址可能会根据开发者策略和平台变化而调整。

项目定位: 这是一个用于自行编译的 OpenWrt 源码,其中包含了大量的中文用户常用插件。

主流仓库地址:

GitHub: 您可以在 GitHub 上搜索 Lean openwrt 或 openwrt-lede 来找到目前活跃的仓库。由于原作者的仓库有时会关闭或变动,建议寻找社区中维护活跃且 Star 数量高的 Fork 或镜像仓库。

 

  • ImmortalWrt(不朽固件)

这是 OpenWrt 在国内社区的一个重要分支项目,旨在更好地服务中国用户,提供更多的本地化功能和硬件支持。

GitHub 源码地址:https://github.com/immortalwrt/immortalwrt

说明: 这是 ImmortalWrt 项目的官方源码仓库,可用于自行编译。

官方固件下载地址:https://downloads.immortalwrt.org/

说明: 这里提供了 ImmortalWrt 的稳定版(如 24.10.4 系列)和开发版快照。

 

  • KoolShare 固件

KoolShare 曾经是国内最知名的路由器固件社区之一,其固件以集成“软件中心”方便安装插件而闻名。

项目定位: 曾经主要以论坛和官方网站发布,现在固件下载和讨论主要集中在相关社区和论坛。

寻找方式: 由于版权和网络环境变化,KoolShare 官方网站的固件下载渠道现在非常不稳定。建议您在路由器相关的技术论坛或贴吧(如恩山无线论坛)中搜索关键词 “KoolShare OpenWrt” 或 “KoolClash”,通常会有热心网友分享针对特定机型的编译版本或下载链接。

 

博主使用了一个23年收藏的一个版本,由于作者不允许共享,这里就不多说明了!虽然这么多版本,但是操作上差不了太多!

 

部署过程

 

创建虚拟机

1,Proxmox 新建虚拟机,名称随意,注意 VM ID(后面会用到)

点击【高级】,选中 【开机自启动】(要不然选择这个做旁路由的主机可能无法上网~)

 

2,操作系统,选择【不使用任何介质】

因为OpenWrt不用ISO镜像安装,直接格式化成硬盘文件即可!

 

 

3,磁盘保持默认设置即可(因为后面会删除掉,不用担心浪费空间

CPU设置,按照自己的情况选择!如果只做旁路由2核 + 1G内存就足够了!

CPU权重,建议该值要比其他虚拟机高一些,数值越大优先级越高!

 

4,网络如图默认即可,然后提交保存即可

 

5,提交成功后,然后进行下一步

 

 

6,硬件 - 硬盘(scsi0) - 分离

7,移除【CD/DVD启动器】和 【硬盘(scsi0)】

 

上传镜像文件

访问 【local(pve)】 - 【ISO镜像】 - 上传 (选择童鞋下载的OpenWrt镜像文件)

镜像文件名称需要留意下,后面会用到!

 

导入镜像文件

点击 【pve】 - 【Shell】准备执行命令

 

 

以下命令得注意几个参数:

102  为 VM ID

xxxxxx.img 为上传的ISO镜像文件名称

替换下面的内容然后执行

qm importdisk 102 /var/lib/vz/template/iso/xxxxxx.img local-lvm

 

 

 

 

挂载硬盘

虚拟机控制台 - 硬件 - 未使用的磁盘 - 编辑

总线/设备  修改为 SATA

 

 

添加开机引导

按图将硬盘添加到引导启动中

 

 

配置OpenWRT

1,启动虚拟机后,可见控制台显示已经启动,但是IP没有

 

2,控制台输入 vi /etc/config/network 修改 lan 节点的 IP为童鞋要设置的

这里涉及到一些Linux命令行操作,不做太详细说明!

  • vi /etc/config/network
  • 按 i  (进去编辑模式)
  • 修改 IP 地址
  • 按 ESC 退出编辑模式
  • 输入 :wq 保存
  • 输入 reboot 重启主机

 

重启成功后,浏览器访问:http://你的IP

 

简单旁路由

这里说说最简单的一种旁路由形式,不同的OpenWrt版本,设置可能不太一致!

目前我家里的内网相对简单!所有设备都在同一个路由器下!网关:192.168.31.1

OpenWrt 设置IP 为 192.168.31.199

当然OpenWrt需要跑一套科学服务,毕竟咱们是要解决访问Github等问题。这部分内容这里不做详细说明!

内网的主机,手机,平板等咋走旁路由呢?

仅需将这些设备网络的网关从 192.168.31.1 改成 192.168.31.199 即可!

这样就解决我们的问题了!这样也是最简单的!其实大部分童鞋家里的网络没有那么复杂!

追求完美的童鞋说,我不想手动改网关?要无缝切换?如何这样的话网络可能略复杂了,本文暂不做说明了。

 

最后说明

1,OpenWrt的各种功能非常强大,旁路由只是其中的小部分功能

2,还有网络多播,AdGuard,DDNS,FRP 等等好玩实用的功能,有兴趣的童鞋搜索玩玩

3,还支持Docker部署服务,可自己部署签到脚本,挂机脚本等等

4,自己想玩玩?但没有小主机?没有能刷固件的路由器?其实自己的电脑安装一套虚拟机就能体验了

5,本文仅作个人纪录分享,请 '键盘侠' 免喷,劳驾绕行

6,有志同道合的童鞋,右上角可加入群组

 

 

 

 

 

 

 

mDNS:Homelab 网络的良药

作者 auto
2024年9月17日 00:00

在 Homelab 中折腾了一段时间后,我发现自己陷入了一个困境:随着设备数量的增加,管理 IP 地址变得越来越痛苦。

典型的场景是这样的:
– SSH 到某台服务器:ssh user@192.168.1.101,等等,101 是哪台机器来着?
– 访问某个服务:`http://192.168.2.88:8080`,这个 88 又是什么?
– 更糟糕的是,DHCP 租约过期后 IP 变了,所有的配置都要改一遍

我尝试过给每台设备绑定静态 IP,但这种方案有几个问题:

  1. IP 地址难以记住:20+ 台设备,每个都要记住对应的 IP
  2. 静态绑定不优雅:在路由器上一个个配置 DHCP 静态绑定很繁琐
  3. 缺乏灵活性:设备迁移到其他网络时需要重新配置

后来我发现了 mDNS(多播域名系统),它完美地解决了这些问题。配置完成后,我可以直接使用 server3.localpfsense.local 这样的域名来访问设备,再也不用记 IP 地址了。

这篇文章记录了我在 OpenWrt + pfSense 双层路由环境下配置 mDNS 的完整过程,包括踩过的坑和解决方案。

我的网络环境

我的网络是两层路由结构:
一级路由:OpenWrt,家庭主路由器,网段 192.168.1.0/24
二级路由:pfSense,虚拟机网络路由器,网段 192.168.2.0/24

这样设置的目的是将虚拟机网络与主网络解耦,让 VM 可以独立运行并组成一个独立的集群。但这也带来了跨网段访问的问题,mDNS 的 reflector 功能正好可以解决这个问题。

路由配置篇

我的一级路由用的是 OpenWrt,二级路由用的是 pfSense。虽然系统不同,但配置思路是类似的。

核心组件是 Avahi,一个开源的 mDNS/DNS-SD 实现。OpenWrt 和 pfSense 都可以直接安装。

OpenWrt 安装配置

安装 Avahi

opkg update
opkg install avahi-daemon-service-ssh avahi-daemon-service-http

修改配置文件

编辑 /etc/avahi/avahi-daemon.conf

[server]
use-ipv4=yes
use-ipv6=yes
check-response-ttl=no
use-iff-running=no
allow-interfaces=br-lan   # 指定监听的网络接口

[publish]
publish-addresses=yes
publish-hinfo=yes
publish-workstation=no
publish-domain=yes

[reflector]
enable-reflector=yes      # 关键:启用 reflector 功能,用于跨网段转发
reflect-ipv=no

[rlimits]
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=30
rlimit-stack=4194304
rlimit-nproc=3

关键配置说明
allow-interfaces=br-lan:指定 Avahi 监听的网络接口
enable-reflector=yes:启用 reflector 功能,这是实现跨网段 mDNS 的核心

参考:

  • https://openwrt.org/docs/guide-developer/mdns
  • https://openwrt.org/docs/guide-user/network/zeroconfig/zeroconf

pfSense 安装配置

安装插件

在 pfSense 的 Package Manager 中搜索并安装 avahi 插件。

关键问题:WAN 接口配置

这里我踩了个坑。pfSense 默认不允许在 WAN 接口启用 mDNS,这是出于安全考虑(如果 WAN 是公网,确实不应该暴露 mDNS)。

但在我的两层路由场景下,二级路由的 WAN 接口连接的是一级路由的 LAN,需要在 WAN 接口启用 mDNS 才能实现跨网段通信。

解决方法:修改插件源码

编辑 /usr/local/www/avahi_settings.php,找到并注释掉 WAN 过滤代码:

// vi /usr/local/www/avahi_settings.php
// 找到两处 wan 的过滤代码,注释掉:
// unset($available_interfaces['wan']);

修改后,在 Web 控制台就可以看到 WAN 选项了,同时选中 WAN 和 LAN 启用。

生成的配置文件

修改后 pfSense 会自动生成配置文件(位于 /usr/local/etc/avahi/avahi-daemon.conf):

这里需要注意:不推荐直接手动修改这个配置文件,因为它会被 GUI 覆盖。建议通过修改 PHP 源码让 GUI 支持 WAN 配置。

参考配置内容

# /usr/local/etc/avahi/avahi-daemon.conf
[server]
allow-interfaces=em0,em1    # WAN 和 LAN 接口
use-ipv4=yes
use-ipv6=no

[publish]
publish-addresses=yes
publish-domain=yes

[reflector]
enable-reflector=yes        # 启用跨网段转发

可选:启用 D-Bus

某些情况下可能需要启用 D-Bus:

mkdir -p /var/run/dbus/
dbus-daemon --system

至此 pfSense 的配置就完成了。

防火墙配置

重要:mDNS 使用 UDP 5353 端口,需要在防火墙中开放此端口。

确保允许以下流量:
– 源:LAN 主机
– 目标:路由器本机(224.0.0.251,mDNS 组播地址)
– 端口:UDP 5353

具体配置方法因路由器而异,在 OpenWrt 或 pfSense 的防火墙规则中添加即可。

主机配置

路由器配置完成后,还需要配置各个主机才能使用 mDNS。我这里以 Ubuntu Server 为例。

设置 Hostname

首先给主机设置一个有意义的 hostname:

sudo hostnamectl set-hostname server3

之后就可以通过 server3.local 访问这台主机了。

配置网络为 DHCP

mDNS 的一大优势是不需要静态 IP,所以把网络配置改为 DHCP:

# 编辑 netplan 配置
vim /etc/netplan/00-installer-config.yaml
network:
  ethernets:
    ens34:
      dhcp4: true
  version: 2
# 应用配置
netplan apply

启用 systemd-resolved 的 mDNS 功能

Ubuntu 新版本使用 systemd-resolved 管理 DNS,需要在这里启用 mDNS:

# 编辑配置文件
vim /etc/systemd/resolved.conf
[Resolve]
MulticastDNS=yes
LLMNR=yes

或者用命令一键修改:

sed -i "s|#MulticastDNS=no|MulticastDNS=yes|g" /etc/systemd/resolved.conf
sed -i "s|#LLMNR=no|LLMNR=yes|g" /etc/systemd/resolved.conf
systemctl restart systemd-resolved

踩坑:Netplan 不支持 mDNS 配置

这里有个大坑。即使修改了 resolved.conf,mDNS 在网络接口上仍然是关闭的:

# 检查接口的 mDNS 状态
resolvectl mdns ens34
# 输出:Link 2 (ens34): no

# 手动启用
resolvectl mdns ens34 yes

但这个设置重启后会失效,因为 Netplan 不支持 mDNS 配置(相关 Bug,2019 年提出至今未修复)。

Netplan 会在 /run 目录下生成配置文件,优先级高于 /etc,导致手动修改无效。

解决方案:创建 systemd 服务

既然是开机自启动的问题,那就用 systemd 来解决:

创建 systemd 服务文件:

cat << EOF > /etc/systemd/system/user-set-mdns@.service
[Unit]
Description=Enable MulticastDNS on network interface
After=systemd-resolved.service

[Service]
ExecStart=resolvectl mdns %i yes

[Install]
WantedBy=multi-user.target
EOF

启用服务(替换 ens34 为你的网卡名称):

sudo systemctl enable user-set-mdns@ens34
sudo systemctl start user-set-mdns@ens34
sudo systemctl status user-set-mdns@ens34

至此,主机的 mDNS 配置就完成了,重启后也会自动生效。

方案二:使用 Avahi(适用于老系统)

如果你的系统没有使用 systemd-resolved(比如老版本的 Ubuntu 或 Debian),可以直接安装 Avahi:

sudo apt-get install avahi-daemon libnss-mdns libnss-mymachines

安装后 Avahi 会自动启动,无需额外配置。

验收测试

配置完成后,让我们测试一下效果。

基本测试

现在可以抛弃 IP 地址,直接使用 .local 域名访问设备:

ping server3.local
ping code-env.local
ping vm-proxy.local
ping pfsense.local
ping openwrt.local

实际使用场景

SSH 连接

# 以前
ssh user@192.168.2.101

# 现在
ssh user@server3.local

访问 Web 服务

# 以前
http://192.168.2.88:8080

# 现在
http://vm-proxy.local:8080

容器配置

# docker-compose.yml
services:
  app:
    environment:
      - DATABASE_URL=postgresql://postgres@db-server.local:5432/mydb

跨网段测试

最重要的是测试跨网段访问,确认 reflector 功能正常工作:

# 从一级网络(192.168.1.x)访问二级网络设备
ping vm-server.local  # 这台设备在 192.168.2.x 网段

# 从二级网络访问一级网络设备
ping openwrt.local    # 这台设备在 192.168.1.x 网段

如果能 ping 通,说明 mDNS reflector 配置成功!

补充说明

二级路由的 IP 配置注意事项

后续重新部署时发现一个问题:如果 pfSense 二级路由使用静态 IP,会导致一级路由无法获取二级的 mDNS 记录。

解决方法
– 在一级路由(OpenWrt)上通过 DHCP 静态绑定给二级路由分配 IP
– 不要在二级路由上直接配置静态 IP
– 配置好后重启二级路由

OpenWrt 防火墙规则(命令行方式)

如果你习惯用命令行配置 OpenWrt 防火墙,可以使用以下命令:

uci -q delete firewall.mdns
uci set firewall.mdns="rule"
uci set firewall.mdns.name="Allow-mDNS"
uci set firewall.mdns.src="*"
uci set firewall.mdns.src_port="5353"
uci set firewall.mdns.dest_ip="224.0.0.251"
uci set firewall.mdns.dest_port="5353"
uci set firewall.mdns.proto="udp"
uci set firewall.mdns.target="ACCEPT"
uci commit firewall
/etc/init.d/firewall restart

配置完 mDNS 已经几个月了,现在回想起来,这是我在 Homelab 中做的最有价值的优化之一。

带来的改变

管理效率提升
– 不再需要维护一个 IP 地址清单
– 设备迁移或重启后不用担心 IP 变化
– 写配置文件时直接用域名,可读性大大提升

实际案例

最近我重装了一台服务器,以前的流程是:
1. 安装系统
2. 登录路由器配置静态 IP 绑定
3. 更新所有相关配置文件中的 IP
4. 重启依赖这台服务器的其他服务

现在的流程:
1. 安装系统
2. 设置 hostname
3. 完事

其他服务根本不需要改配置,因为它们用的是 server3.local 这样的域名,自动就能找到新的 IP。

一些建议

命名规范很重要

建议给设备起一个有意义的 hostname:
nas.local 而不是 server1.local
pve-node1.local 而不是 vm1.local
k8s-master.local 而不是 ubuntu-001.local

好的命名可以让你半年后还记得这台设备是干什么的。

文档还是要有的

虽然不用记 IP 了,但建议维护一个简单的设备清单:
– 设备名称和 hostname
– 主要用途和运行的服务
– 重要配置文件位置

安全性考虑

mDNS 只适合内网使用,不要在公网暴露:
– 路由器 WAN 口不要启用 mDNS
– 如果有公网 IP,确保防火墙规则正确
– mDNS 流量不应该离开你的局域网

总结

mDNS 确实是 Homelab 的良药。它解决了 IP 地址管理的痛点,让网络配置更加灵活和优雅。虽然配置过程有一些坑(特别是 Netplan 的问题),但一旦配置好,体验提升是显著的。

如果你也在运营 Homelab,强烈建议试试 mDNS。配置时间不会超过一个下午,但带来的便利是长期的。

希望这篇文章能够帮助你顺利配置 mDNS,少走一些弯路。

参考链接

OpenWrt如何启用DoH?让软路由下的设备使用 DNS over HTTPS

2025年9月12日 18:30
这篇文章介绍了在istoreos软路由中实现DoH(DNS over HTTPS)的步骤。由于系统仅支持IP形式的DNS,需通过安装https-dns-proxy及相关luci界面包实现。完成后可在网页“HTTPS DNS代理”中删除默认实例,新增如阿里和腾讯的服务提供商,并分别设置不同端口。引导DNS仅用于解析DoH地址,实际配置可在/etc/config/https-dns-proxy查看。文章提醒是否开启强制路由器DNS要根据实际需求决定,一般建议关闭。同时说明无需修改WAN、LAN DNS,因设备最终解析均通过DoH完成,从而实现加密安全的DNS服务。

Cudy TR3000 吃鹅(daed)记

2025年2月28日 21:18

缘起

前不久在京东自营看到我馋了很久的 Cudy TR3000 有 ¥153 的折扣价,虽然比起 ¥130 的史低价(甚至 ¥110 的凑单史低价)还有些距离,但已经到我的可接受范围内了,于是果断下单剁手了这台我心心念念的 Cudy TR3000 迷你路由器,以此来缓解我的开学前综合症(一种精神性疾病)

这台路由器使用 Type-C 供电,拥有一个 2.5Gbps 的 WAN 口和一个 1Gbps 的 LAN 口,在此基础上还有一个 USB 口可用于打印机共享、挂载外接存储、安卓手机 USB 共享网络等多种用途。更让我心动的地方在于其小巧的体型,非常适合出差、旅行、短期租房等场景。考虑到接下来一段实习可能会有租房需求,于是便趁此机会果断下单了。

与一台小米8的宽高对比

官方系统是基于 openwrt 定制的,功能比较单一,因此考虑刷入 openwrt 原版系统增加可玩性。在恩山无限论坛上发现已经有人编译了基于 Linux 6.6 版本的 OpenWRT 系统,这已经满足了 dae 的 Bind to LAN 功能的内核版本要求( >= 5.17 ),且 512MB 的内存大小刚好达到了推荐的最小内存大小,于是这 dae 肯定是要试着吃一吃的。如果成功了,这就是我手上第一台吃上大鹅的硬路由。


开始刷机

路由器官方系统的后台管理地址是 192.168.10.1,初次进入会要求你设置密码,然后就是一路随便点,完成初始化,随后就进入到主页。我手上这台的 FW 版本号是 2.3.2-20241226,不清楚后续的版本能不能仍然使用这套方案。

过渡固件

首先我们需要先刷入所谓的「过渡固件」。刷入过渡固件的意义在于,这个过渡固件能被官方系统的升级程序所承认,这样就允许我们进行后续的操作。

过渡固件的文件名和 md5 值如下:

b8333d8eebd067fcb43bec855ac22364  cudy_tr3000-v1-sysupgrade.bin

随后我们可以在路由器的管理页面的基本设置中找到固件升级的地方,在本地更新一栏中选择过渡固件上传更新即可。

刷入解锁 FIP 分区写入权限的固件

刷入过渡固件后稍等大约一分钟,路由器的 DHCP 重新工作,我们就可以通过 192.168.1.1 进入过渡固件的管理页面。

初次登陆时没有密码,随便输就能登陆成功。考虑到后续可能会有恢复出厂的需求,建议在这一步对 FIP 分区进行备份。

这次我们需要刷入下面这个 LEDE 固件来解锁 FIP 分区的写入权限,文件名和 md5 仍然放在下面

4af5129368cbf0d556061f682b1614f2  openwrt-mediatek-filogic-cudy_tr3000-v1-squashfs-sysupgrade.bin

在下方选择刷入固件,上传我们本次需要刷入的固件,刷入。

刷入 uboot

再等待一分钟左右,电脑重新连接上路由器后,我们可以进入到这个解锁了 FIP 分区写入权限的固件,默认密码是 password

在侧栏选择文件传输,将本次要刷入的 uboot 上传,文件名和 md5 还是放在下面。注意 zip 包要解压

e5ff31bac07108b6ac6cd63189b4d113  dhcp-mt7981_cudy_tr3000-fip-fixed-parts-multi-layout.bin

随后侧栏进入 TTYD 终端,输入默认的用户名密码 root / password,执行命令刷入 uboot

mtd write /tmp/upload/dhcp-mt7981_cudy_tr3000-fip-fixed-parts-multi-layout.bin FIP

刷入自编译的 immortalwrt

刷入 uboot 以后,给路由器断电,确保网线分别连接电脑和路由器 LAN 口后,按住 reset 键再插入电源键,直至白灯闪烁四次后转为红灯后松开 reset 键,即可进入 uboot。

我编译的是 112m 的布局,因此需要选择 mod-112m 这个 mtd 布局后上传固件刷入。

8c9a44f29c8c5a0617e61d49bf8ad45d  112m-immortalwrt-cudy_tr3000-ebpf_by_zhullyb_20250325-squashfs-sysupgrade.bin

再次等待电脑重新连接路由器,这是最终吃上 daed 的系统了,依然是没有默认密码,随便输入即可进入。在连接上网络后,在系统 - 软件包页面,更新软件包列表。

随后就可以安装 dae / daed 相关软件了,可视需求选择 luci-i18n-dae-zh-cn 或者 luci-i18n-daed-zh-cn,其他包会作为依赖一同被安装。我这里安装的是 daed。

安装后刷新界面,我们就可以在顶栏的服务板块看到 daed。

daed 正常运行,能正常跑满我家的 300Mbps 宽带下行(单线程实测 250Mbps),速度峰值时 CPU 占用图如下。

多线程测速

单线程测速

文章中提到的文件

https://www.123684.com/s/gfprVv-wEQ8d

https://www.123912.com/s/gfprVv-wEQ8d

参见

从零开始!在红米AX6000路由器上刷入Openwrt

作者 GamerNoTitle
2024年11月10日 21:26

在我前两天搞定TPLINK后,近期跟我聊到路由器的同学买了个红米的AX6000,想自己刷,发现自己搞不定了求助于我,于是我们一起刷这台路由器,就有了这篇教程

准备工作

首先得把小米路由器的系统降级,这位同学拿过来的时候,他降级到了1.0.60,所以降级过程就没有什么教程啦,可以去网上找找旧版的包,然后直接通过路由器管理面板的升级部分刷就行了

打开Telnet(路由器的开发者模式)

我们降级好路由器后,先要打开telnet,才能打开SSH,打开telnet的过程不要联网!!!

实测联网会打不开telnet

首先我们要登录进路由器的管理面板,在管理面板的地址栏中有我们需要的stok,例如http://192.168.31.1/cgi-bin/luci/;stok=71871cc803318e6f85e9c73d2ed7736c,这个stok=后面的内容就是我们需要的stok,我们复制下来,替换掉下面链接中的{stok},并复制到浏览器访问(访问的结果统一会显示{code: 0},四次访问都是,不再赘述,我使用的是curl)

http://192.168.31.1/cgi-bin/luci/;stok={stok}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20zz%3D%24%28dd%20if%3D%2Fdev%2Fzero%20bs%3D1%20count%3D2%202%3E%2Fdev%2Fnull%29%20%3B%20printf%20%27%A5%5A%25c%25c%27%20%24zz%20%24zz%20%7C%20mtd%20write%20-%20crash%20%3B%20

http://192.168.31.1/cgi-bin/luci/;stok={stok}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20

访问了以后路由器会重启,重启完了以后,我们再登录到路由器管理面板,此时stok会改变,我们复制新的stok,替换下面链接中的{stok},然后丢到浏览器访问

http://192.168.31.1/cgi-bin/luci/;stok={stok}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20bdata%20set%20telnet_en%3D1%20%3B%20bdata%20set%20ssh_en%3D1%20%3B%20bdata%20set%20uart_en%3D1%20%3B%20bdata%20commit%20%3B%20

此链接跟第二条一样,都是重启用的

http://192.168.31.1/cgi-bin/luci/;stok={stok}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20

我们打开一个能够支持telnet连接的软件,用户名和密码都是空,就可以连接进去了

自动化脚本

于是我随手撸了一个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import httpx

host = "http://192.168.31.1"

# First time
stok = input("请输入第一次的stok: ")

BASE = host + "/cgi-bin/luci/;stok="

MTD_WRITE_ROUTE = "/api/misystem/set_sys_time?timezone=%20%27%20%3B%20zz%3D%24%28dd%20if%3D%2Fdev%2Fzero%20bs%3D1%20count%3D2%202%3E%2Fdev%2Fnull%29%20%3B%20printf%20%27%A5%5A%25c%25c%27%20%24zz%20%24zz%20%7C%20mtd%20write%20-%20crash%20%3B%20"
REBOOT_ROUTE = "/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20"
ENABLE_TALNET_ROUTE = "/api/misystem/set_sys_time?timezone=%20%27%20%3B%20bdata%20set%20telnet_en%3D1%20%3B%20bdata%20set%20ssh_en%3D1%20%3B%20bdata%20set%20uart_en%3D1%20%3B%20bdata%20commit%20%3B%20"

response = httpx.get(BASE + stok + MTD_WRITE_ROUTE)
print(response.json())
response = httpx.get(BASE + stok + REBOOT_ROUTE)
print(response.json())

# Second time
stok = input("请输入第二次的stok: ")
response = httpx.get(BASE + stok + ENABLE_TALNET_ROUTE)
print(response.json())
response = httpx.get(BASE + stok + REBOOT_ROUTE)
print(response.json())

打开SSH

打开任意telnet客户端通过telnet连接后,我们需要打开SSH

设置root密码

通过下面的命令可以设置root的密码为admin

1
$ echo -e 'admin\nadmin' | passwd root

其实就是运行passwd root,然后输入了两次admin而已,你也可以自己改

打开SSH

接着我们运行下面的命令打开SSH

1
2
3
4
5
6
7
8
9
bdata set boot_wait=on
bdata commit
nvram set ssh_en=1
nvram set telnet_en=1
nvram set uart_en=1
nvram set boot_wait=on
nvram commit
sed -i 's/channel=.*/channel="debug"/g' /etc/init.d/dropbear
/etc/init.d/dropbear restart

输入后是不会有任何输出的,此时SSH就已经打开了

设置SSH开机自动启动

接着我们要设置开机开启SSH,要不然重启一下就没了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
mkdir -p /data/auto_ssh && cd /data/auto_ssh

cat <<EOF > auto_ssh.sh
#!/bin/sh

auto_ssh_dir="/data/auto_ssh"
host_key="/etc/dropbear/dropbear_rsa_host_key"
host_key_bk="${auto_ssh_dir}/dropbear_rsa_host_key"

unlock() {
# Restore the host key.
[ -f \$host_key_bk ] && ln -sf \$host_key_bk \$host_key

# Enable telnet, ssh, uart and boot_wait.
[ "\$(nvram get telnet_en)" = 0 ] && nvram set telnet_en=1 && nvram commit
[ "\$(nvram get ssh_en)" = 0 ] && nvram set ssh_en=1 && nvram commit
[ "\$(nvram get uart_en)" = 0 ] && nvram set uart_en=1 && nvram commit
[ "\$(nvram get boot_wait)" = "off" ] && nvram set boot_wait=on && nvram commit

[ "\$(uci -c /usr/share/xiaoqiang get xiaoqiang_version.version.CHANNEL)" != 'stable' ] && {
uci -c /usr/share/xiaoqiang set xiaoqiang_version.version.CHANNEL='stable'
uci -c /usr/share/xiaoqiang commit xiaoqiang_version.version 2>/dev/null
}

channel=\$(/sbin/uci get /usr/share/xiaoqiang/xiaoqiang_version.version.CHANNEL)
if [ "\$channel" = "release" ]; then
sed -i 's/channel=.*/channel="debug"/g' /etc/init.d/dropbear
fi

if [ -z "\$(pidof dropbear)" -o -z "\$(netstat -ntul | grep :22)" ]; then
/etc/init.d/dropbear restart 2>/dev/null
/etc/init.d/dropbear enable
fi
}

install() {
# unlock SSH.
unlock

# host key is empty, restart dropbear to generate the host key.
[ -s \$host_key ] || /etc/init.d/dropbear restart 2>/dev/null

# Backup the host key.
if [ ! -s \$host_key_bk ]; then
i=0
while [ \$i -le 30 ]
do
if [ -s \$host_key ]; then
cp -f \$host_key \$host_key_bk 2>/dev/null
break
fi
let i++
sleep 1s
done
fi

# Add script to system autostart
uci set firewall.auto_ssh=include
uci set firewall.auto_ssh.type='script'
uci set firewall.auto_ssh.path="\${auto_ssh_dir}/auto_ssh.sh"
uci set firewall.auto_ssh.enabled='1'
uci commit firewall
echo -e "\033[32m SSH unlock complete. \033[0m"
}

uninstall() {
# Remove scripts from system autostart
uci delete firewall.auto_ssh
uci commit firewall
echo -e "\033[33m SSH unlock has been removed. \033[0m"
}

main() {
[ -z "\$1" ] && unlock && return
case "\$1" in
install)
install
;;
uninstall)
uninstall
;;
*)
echo -e "\033[31m Unknown parameter: \$1 \033[0m"
return 1
;;
esac
}

main "\$@"
EOF

chmod +x auto_ssh.sh

# 设置自动启动
uci set firewall.auto_ssh=include
uci set firewall.auto_ssh.type='script'
uci set firewall.auto_ssh.path='/data/auto_ssh/auto_ssh.sh'
uci set firewall.auto_ssh.enabled='1'
uci commit firewall

这个文件你也可以放在别的位置,自己修改上面脚本里面的文件位置就行,不过要注意重启是否会消失,有些路由器重启会自动清除文件的(例如我前阵子弄的WAR308)

设置时区

最后一步是设置时区,使用下面的命令设置时区

1
2
3
4
uci set system.@system[0].timezone='CST-8'
uci set system.@system[0].webtimezone='CST-8'
uci set system.@system[0].timezoneindex='2.84'
uci commit

关闭开发者模式

使用下面的命令关闭开发者模式

1
mtd erase crash

最后是重启,直接打reboot就行了

通过SSH刷入uboot

当我们通过SSH连接进路由器后,我们需要保证路由器可以联网,然后运行下面的命令

1
$ cd /tmp && curl --silent -O https://fastly.jsdelivr.net/gh/miaoermua/unlock-redmi-ax6000@main/uboot.sh && chmod +x uboot.sh && ./uboot.sh

运行了以后,脚本会帮你备份你的分区文件,记得把它们弄出来,要不然没办法恢复原厂系统,分别是/tmp/mtd5_FIP.bin/tmp/mtd4_Factory.bin

拿出来以后,再运行下面的命令来刷入uboot,最后会弹出一行success,就说明完成了

1
2
3
mtd erase FIP
mtd write /tmp/mt7986_redmi_ax6000-fip-fixed-parts.bin FIP
mtd verify /tmp/mt7986_redmi_ax6000-fip-fixed-parts.bin FIP

进入uboot,刷入openwrt系统

进入uboot模式

先拔掉电源,然后用牙签/卡针之类的尖锐的东西,戳着reset键,然后插上电源等待15秒以上,就可以松开了,这个就可以用电脑访问uboot了

uboot模式下,路由器的灯不会亮

电脑访问uboot

在进入uboot之前,请先把自己的电脑的ip地址修改一下,因为uboot模式下没有DHCP

然后访问http://192.168.31.1进入uboot,界面应该是像下面这样的

我们尝试了下面的两个系统(因为我这个同学记错路由器的空间大小以为CatWrt的分区大小给小了于是刷了ImmortalWrt)

刷入系统

下载好你需要的系统包后,直接在uboot里面上传,上传后会读条,这个时候路由器在校验系统包和计算md5,直接点击update就可以了

第一次刷可能会出现下图这样的fail提示,我们返回重新上传刷一次就行了

刷好了访问系统包对应的ip地址就可以进入openwrt了

其他

进入openwrt后,发现这个机子的存储应该是256MB(图片是CatWrt的终端)

内存为512MB左右

END

怎么说呢,这次应该是我第一次真正去刷品牌路由器成功的,我以前刷过小米的AX3000T但是刷炸了;讲真,品牌路由器的内存和存储还是给得太小了

当然这次成功也离不开下面这些参考文档(注:里面有些链接是过期的,所以为什么我会综合起来写一篇文,就是避免其他人做到一半发现链接404不知道怎么做了)

ALL IN ALL,刷路由器还是很好玩的 :D

Ref:

https://docs.qq.com/doc/DS1RlUVhUYXp3YnhL

https://www.right.com.cn/forum/thread-8261104-1-1.html

https://blog.csdn.net/sxf1061700625/article/details/130328437

真正的END

因为我发现我们学校会BAN我的MAC地址,于是我顺带放出我写的MAC地址更换脚本(可以设置计划任务)

MAC备份还原脚本

避免你需要还原你路由器真正的mac的时候找不到mac,建议你用这个先备份一下你路由器的mac

如果你的网口不是eth0,请先更换一下网口!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/sh

MAC_FILE="/root/mac"

# 获取当前MAC地址并保存到文件
save_mac() {
CURRENT_MAC=$(ip link show eth0 | grep ether | awk '{print $2}')
echo "当前的MAC地址是: $CURRENT_MAC"
echo "$CURRENT_MAC" > "$MAC_FILE"
echo "已保存当前MAC地址到 $MAC_FILE"
}

# 从文件中恢复MAC地址
restore_mac() {
if [ -f "$MAC_FILE" ]; then
SAVED_MAC=$(cat "$MAC_FILE")
echo "从文件恢复MAC地址: $SAVED_MAC"
ip link set dev eth0 down
ip link set dev eth0 address "$SAVED_MAC"
ip link set dev eth0 up
echo "已恢复MAC地址到eth0"
else
echo "MAC文件不存在,无法恢复MAC地址"
fi
}

# 检查参数并执行对应的操作
if [ "$1" = "save" ]; then
save_mac
elif [ "$1" = "restore" ]; then
restore_mac
else
echo "用法: $0 {save|restore}"
echo "save: 保存当前的MAC地址"
echo "restore: 恢复之前保存的MAC地址"
fi

Mac生成替换脚本

我这里设置了固定的前缀,是因为我路由器的MAC地址带了这三个,建议改成自己的

如果你的网口不是eth0,请先更换一下网口!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh

# 生成一个随机的MAC地址
generate_mac() {
PREFIX="c6:1f:d8"
# 使用 /dev/urandom 获取随机数
HEX1=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom)
HEX2=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom)
HEX3=$(hexdump -n 1 -e '1/1 "%02X"' /dev/urandom)
echo "$PREFIX:$HEX1:$HEX2:$HEX3"
}

# 获取新的MAC地址
NEW_MAC=$(generate_mac)
echo "生成的新MAC地址为: $NEW_MAC"

# 使用新的MAC地址修改eth0的MAC地址
ip link set dev eth0 down
ip link set dev eth0 address $NEW_MAC
ip link set dev eth0 up

# 验证修改是否成功
ip link show eth0 | grep ether

Openwrt备份备份恢复脚本

注意修改前两行

1
2
3
4
5
# 定义备份目录
BACKUP_DIR="/mnt/usb1-1"

# 定义 OpenWrt 系统路径
OPENWRT_MMC="/dev/mmcblk0"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!/bin/ash

# OpenWrt 备份与恢复管理脚本
# 支持命令行参数快速备份:--owrt-backup --config-backup --iptables-backup --firewall-backup --all-backup

# 定义备份目录
BACKUP_DIR="/mnt/usb1-1"

# 系统参数
OPENWRT_MMC="/dev/mmcblk0"
FIREWALL_CONFIG="/etc/config/firewall"

# 备份子目录
OPENWRT_BACKUP_DIR="$BACKUP_DIR/openwrt-backup"
OPENWRT_CONFIG_BACKUP_DIR="$BACKUP_DIR/openwrt-config-backup"
IPTABLES_BACKUP_DIR="$BACKUP_DIR/iptables-backup"
FIREWALL_BACKUP_DIR="$BACKUP_DIR/firewall-backup"

# 初始化目录
mkdir -p $OPENWRT_BACKUP_DIR $OPENWRT_CONFIG_BACKUP_DIR $IPTABLES_BACKUP_DIR $FIREWALL_BACKUP_DIR

# 获取当前日期
CURRENT_DATE=$(date +%Y%m%d)

# 定义颜色代码
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
RESET='\033[0m'

#######################################
# 核心备份功能函数
#######################################

backup_full_image() {
echo -e "${BLUE}[1/4] 开始备份系统镜像...${RESET}"
local temp_bin="$OPENWRT_BACKUP_DIR/temp_${CURRENT_DATE}.bin"
local backup_file="$OPENWRT_BACKUP_DIR/openwrt-backup-${CURRENT_DATE}.tar.gz"

# 创建磁盘镜像
if ! dd if="$OPENWRT_MMC" of="$temp_bin" bs=1M; then
echo -e "${RED}错误:磁盘镜像创建失败!${RESET}"
return 1
fi

# 压缩备份
if tar -czf "$backup_file" -C "$OPENWRT_BACKUP_DIR" $(basename $temp_bin); then
md5sum $backup_file > ${backup_file}.md5
echo -e "${GREEN}系统镜像备份成功:${backup_file}${RESET}"
else
echo -e "${RED}错误:压缩备份失败!${RESET}"
fi
rm -f $temp_bin
}

restore_full_image() {
echo -e "${BLUE}[系统恢复] 请选择备份文件:${RESET}"
ls -lh $OPENWRT_BACKUP_DIR/openwrt-backup-*.tar.gz 2>/dev/null || { echo -e "${RED}未找到备份文件!${RESET}"; return; }

read -p "请输入要恢复的文件名: " backup_file
local full_path="$OPENWRT_BACKUP_DIR/$backup_file"

# 验证文件
[ ! -f "$full_path" ] && echo -e "${RED}文件不存在!${RESET}" && return
[ ! -f "${full_path}.md5" ] && echo -e "${YELLOW}警告:未找到MD5校验文件${RESET}" || (md5sum -c "${full_path}.md5" || { echo -e "${RED}MD5校验失败!${RESET}"; return; })

# 确认操作
read -p "确定要恢复系统镜像吗?此操作不可逆![y/N]: " confirm
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && return

# 解压并恢复
echo -e "${BLUE}正在解压镜像文件...${RESET}"
local temp_bin="${full_path%.tar.gz}.bin"
tar -xzf "$full_path" -C "$OPENWRT_BACKUP_DIR" || { echo -e "${RED}解压失败!${RESET}"; return; }

echo -e "${BLUE}正在写入系统镜像...${RESET}"
if dd if="$temp_bin" of="$OPENWRT_MMC" bs=1M; then
echo -e "${GREEN}系统恢复成功,请重启设备!${RESET}"
else
echo -e "${RED}镜像写入失败!${RESET}"
fi
rm -f $temp_bin
}

backup_config() {
echo -e "${BLUE}[2/4] 备份系统配置...${RESET}"
local backup_file="$OPENWRT_CONFIG_BACKUP_DIR/openwrt-config-backup-${CURRENT_DATE}.bak"
if sysupgrade -b $backup_file; then
md5sum $backup_file > ${backup_file}.md5
echo -e "${GREEN}系统配置备份成功:${backup_file}${RESET}"
else
echo -e "${RED}错误:配置备份失败!${RESET}"
fi
}

restore_config() {
echo -e "${BLUE}[配置恢复] 请选择备份文件:${RESET}"
ls -lh $OPENWRT_CONFIG_BACKUP_DIR/openwrt-config-backup-*.bak 2>/dev/null || { echo -e "${RED}未找到备份文件!${RESET}"; return; }

read -p "请输入要恢复的文件名: " backup_file
local full_path="$OPENWRT_CONFIG_BACKUP_DIR/$backup_file"

# 验证文件
[ ! -f "$full_path" ] && echo -e "${RED}文件不存在!${RESET}" && return
[ ! -f "${full_path}.md5" ] && echo -e "${YELLOW}警告:未找到MD5校验文件${RESET}" || (md5sum -c "${full_path}.md5" || { echo -e "${RED}MD5校验失败!${RESET}"; return; })

# 确认操作
read -p "确定要恢复系统配置吗?[y/N]: " confirm
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && return

# 创建临时备份
local current_backup="$OPENWRT_CONFIG_BACKUP_DIR/current_config_$(date +%H%M%S).bak"
sysupgrade -b $current_backup || { echo -e "${RED}当前配置备份失败,已中止恢复!${RESET}"; return; }

# 执行恢复
if sysupgrade -r $full_path; then
echo -e "${GREEN}配置恢复成功,正在重启网络服务...${RESET}"
/etc/init.d/network restart
else
echo -e "${RED}配置恢复失败!${RESET}"
fi
}

backup_iptables() {
echo -e "${BLUE}[3/4] 备份iptables规则...${RESET}"
local backup_file="$IPTABLES_BACKUP_DIR/iptables-backup-${CURRENT_DATE}.bak"
if iptables-save > $backup_file; then
md5sum $backup_file > ${backup_file}.md5
echo -e "${GREEN}iptables备份成功:${backup_file}${RESET}"
else
echo -e "${RED}错误:iptables备份失败!${RESET}"
fi
}

restore_iptables() {
echo -e "${BLUE}[iptables恢复] 请选择备份文件:${RESET}"
ls -lh $IPTABLES_BACKUP_DIR/iptables-backup-*.bak 2>/dev/null || { echo -e "${RED}未找到备份文件!${RESET}"; return; }

read -p "请输入要恢复的文件名: " backup_file
local full_path="$IPTABLES_BACKUP_DIR/$backup_file"

# 验证文件
[ ! -f "$full_path" ] && echo -e "${RED}文件不存在!${RESET}" && return
[ ! -f "${full_path}.md5" ] && echo -e "${YELLOW}警告:未找到MD5校验文件${RESET}" || (md5sum -c "${full_path}.md5" || { echo -e "${RED}MD5校验失败!${RESET}"; return; })

# 确认操作
read -p "确定要恢复iptables规则吗?[y/N]: " confirm
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && return

if iptables-restore < $full_path; then
echo -e "${GREEN}iptables规则恢复成功!${RESET}"
else
echo -e "${RED}规则恢复失败,请检查文件格式!${RESET}"
fi
}

backup_firewall() {
echo -e "${BLUE}[4/4] 备份防火墙配置...${RESET}"
local backup_file="$FIREWALL_BACKUP_DIR/firewall-backup-${CURRENT_DATE}.bak"
if cp $FIREWALL_CONFIG $backup_file; then
md5sum $backup_file > ${backup_file}.md5
echo -e "${GREEN}防火墙配置备份成功:${backup_file}${RESET}"
else
echo -e "${RED}错误:防火墙配置备份失败!${RESET}"
fi
}

restore_firewall() {
echo -e "${BLUE}[防火墙恢复] 请选择备份文件:${RESET}"
ls -lh $FIREWALL_BACKUP_DIR/firewall-backup-*.bak 2>/dev/null || { echo -e "${RED}未找到备份文件!${RESET}"; return; }

read -p "请输入要恢复的文件名: " backup_file
local full_path="$FIREWALL_BACKUP_DIR/$backup_file"

# 验证文件
[ ! -f "$full_path" ] && echo -e "${RED}文件不存在!${RESET}" && return
[ ! -f "${full_path}.md5" ] && echo -e "${YELLOW}警告:未找到MD5校验文件${RESET}" || (md5sum -c "${full_path}.md5" || { echo -e "${RED}MD5校验失败!${RESET}"; return; })

# 确认操作
read -p "确定要恢复防火墙配置吗?[y/N]: " confirm
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && return

# 备份当前配置
local current_backup="$FIREWALL_BACKUP_DIR/current_firewall_$(date +%H%M%S).bak"
cp $FIREWALL_CONFIG $current_backup || { echo -e "${RED}当前配置备份失败,已中止恢复!${RESET}"; return; }

if cp $full_path $FIREWALL_CONFIG; then
echo -e "${GREEN}防火墙配置恢复成功,正在重启服务...${RESET}"
/etc/init.d/firewall restart
else
echo -e "${RED}配置恢复失败!${RESET}"
fi
}

#######################################
# 命令行参数处理
#######################################

print_banner() {
echo -e "${YELLOW}"
echo " _ _ _ _ _"
echo " _____ ___ __| |_ _ _| |_(_) | ___| |__"
echo " / _ \ \ /\ / / '__| __|____| | | | __| | | / __| '_ \\"
echo "| (_) \ V V /| | | ||_____| |_| | |_| | |_\__ \ | | |"
echo " \___/ \_/\_/ |_| \__| \__,_|\__|_|_(_)___/_| |_|"
echo -e "${RESET}"
echo -e "${BLUE} —— OpenWrt备份工具 @GamerNoTitle${RESET}"
echo -e "${BLUE} https://bili33.top${RESET}\n"
}

if [ $# -gt 0 ]; then
print_banner
echo -e "${GREEN}检测到命令行参数,进入快速备份模式...${RESET}"

# 处理多个参数
for param in "$@"; do
case $param in
--owrt-backup) backup_full_image ;;
--config-backup) backup_config ;;
--iptables-backup) backup_iptables ;;
--firewall-backup) backup_firewall ;;
--all-backup)
backup_full_image
backup_config
backup_iptables
backup_firewall
;;
*) echo -e "${RED}错误:未知参数 $param${RESET}"; exit 1 ;;
esac
done
exit 0
fi

#######################################
# 交互式菜单系统
#######################################

show_menu() {
clear
print_banner
echo -e "${YELLOW}======================= owrt-util.sh ========================${RESET}"
echo -e "${YELLOW} OpenWrt 备份与恢复管理脚本 ${RESET}"
echo -e "${YELLOW} https://bili33.top ${RESET}"
echo -e "${YELLOW}=============================================================${RESET}"
echo "1. 完整系统备份 (磁盘镜像)"
echo "2. 系统配置备份"
echo "3. iptables规则备份"
echo "4. 防火墙配置备份"
echo "5. 一键全量备份"
echo -e "${YELLOW}-------------------------------------------------------------${RESET}"
echo "6. 恢复系统镜像"
echo "7. 恢复系统配置"
echo "8. 恢复iptables规则"
echo "9. 恢复防火墙配置"
echo -e "${YELLOW}-------------------------------------------------------------${RESET}"
echo "0. 退出"
echo -e "${YELLOW}=============================================================${RESET}"
echo -n "请输入选择: "
}


while true; do
show_menu
read choice
case $choice in
1) backup_full_image ;;
2) backup_config ;;
3) backup_iptables ;;
4) backup_firewall ;;
5)
backup_full_image
backup_config
backup_iptables
backup_firewall
;;
6) restore_full_image ;;
7) restore_config ;;
8) restore_iptables ;;
9) restore_firewall ;;
0) exit 0 ;;
*) echo -e "${RED}无效输入,请重新选择!${RESET}" ;;
esac
echo -e "\n${BLUE}按回车返回菜单...${RESET}"
read
done

OpenWrt+R66s 软路由入门尝鲜

作者 mythsman
2023年1月11日 15:46

背景

随着家里电子设备越来越多,客户端维度的科学上网配置已经逐渐支持不了日常需求了:

  1. 设备数量越来越多;配置不过来,且容易触发机场的客户端连接上限。
  2. 设备类型越来越多;安卓端、IPhone端、IPAD端、Mac端、树莓派端、PC端、Kindle端,需要的客户端各不相同,配置的思维负担太大,甚至有些类型的设备没有靠谱的客户端。
  3. PAC规则越来越多;自己通常会有一个主要用的PAC规则,但是当换设备后,就需要重新配置,非常麻烦。

于是趁着工作之闲,研究了一下软路由,一站式解决了家庭上网问题。

硬件选购

市场上的可自由刷机的路由器还是很多的,不过对于入门级屌丝租客党来说,明白自己到底需要什么是很重要的:

  1. 不需要 WIFI 功能。移动光猫自带 WIFI 功能,软路由只需专注做网关服务器即可。后续如果对 WIFI 有更高要求再另买专用的 WIFI。所谓专业的东西做专业的事。
  2. 不需要 HDMI 功能。带 HDMI 功能的基本都是定位于迷你主机或者电视盒子的,其实做路由器根本用不到。
  3. 网口并不需要太多。考虑到家庭设备都是用光猫自带的WIFI连接,因此不需要很多网口。最低一个 LAN 口其实就足矣。
  4. 性能并不需要太高。毕竟租房的时候办的也就是200M带宽,网线再快也没用。同时家里也没搞什么视频工作站,内网也基本没啥带宽。况且性能高了的话、耗电、散热、占地都是问题。
  5. 芯片尽可能新一点。芯片类产品买新不买旧,就算不太在乎性能,也得考虑性价比,少买老古董不做垃圾佬。
  6. 尽量支持卡刷。线刷基本都需要去官方文档上查流程,比较麻烦。而卡刷的流程几乎都是一样的,拔卡写镜像开机即可。

基于上述原则,类似小米AX6000之类的 WIFI 路由器基本不会考虑了;类似J4125之类的性能较强、耗电较高的基于 X86 的路由器基本也不会考虑了;类似 R2s ,N1盒子之类的老东西也不考虑了。

搜寻了一番,发现电犀牛(FastRhino)的 R66s 刚好符合我的基本要求。

  • 接口和大小刚合适。两个2.5G网口、两个USB3.0口、使用SD卡、无HDMI口,因此十分小巧。
  • 产品和芯片比较新。产品是2022年5月发布,瑞芯微(Rockchip)RK3568芯片。
  • 性价比较高。2G内存+32G卡配置到手320¥不到。

相比一些从电视盒子改来的玩意、或者羞羞答答才放开刷机功能的WIFI路由器、或者是仗着原装OpenWrt割韭菜的路由器来说,这个产品还是比较大胆和良心的。

固件选择

OpenWrt官方固件自然也是可以的,不过考虑到国人的常用需求,一般都是用国内维护的固件。常见的固件有:

  1. Lean 的 LEDE 固件(官网)。
  2. 易有云的 iStoreOS 固件(官网)。
  3. Flippy 的固件(官网)。

个人感觉这些固件其实都大同小异,主要区别还是上游的 OpenWrt 版本不同、Linux 内核版本不同、默认自带的软件包不同(尤其是 iStoreOS 自带了很多私货应用)。其实 R66s 出厂自带的镜像也是够用的(其实就是 Lean 的固件),只是出于政策原因,没有自带科学上网工具。这些东西动动小手自己装下也行,不过为了方便大家开箱即用,直接写到固件里用起来更方便而已。

如果需要自己刷机,其实也不复杂。用读卡器插入PC,用 rufus 工具直接写入指定镜像即可。

这里还遇到了有一个有意思的点,原装的 32G SD 卡插进来之后,Windows系统的文件管理器只识别出了 64MB。原本以为是遇到了奸商,但是用磁盘管理工具一看的确是 32G 的盘。后来研究后才发现是因为这个是系统引导盘,因此有时只会识别系统主分区的大小,有时甚至不会被识别为外部存储,不影响使用。

正常刷完后,SD 卡分区大致如下。只使用了主分区,还有大量未分配的区域,如有需要等启动后再新增分区即可。

网络设计

相关背景知识可以先看一下油管 jack stone的家庭网络设计,讲的挺好,颇有老司机风范。

考虑到我这里光猫自带的WIFI也够用,但是光猫后台没有admin权限,很多东西不好改。并且出于社恐也不想打电话找宽带师傅把光猫的路由模式改桥接模式。因此我还是采用了 光猫做主路由+R66s做旁路由 的方案:

  1. 软路由和光猫以 LAN口-LAN口相连。
  2. 整个网络中只使用光猫的网段和光猫的DHCP服务。
  3. 光猫不做任何配置,由接入的客户端手动配置网关和 DNS 到软路由。

网络配置

对于新手小白来说,这一步最容易踩坑。尤其是当接线和配置不对时,连后台都打不开,这是最让人沮丧的。我个人也是尝试了很多姿势才了解其中的弯弯绕。

错误姿势:软路由LAN口直接接光猫LAN口

唉?前面不是说软路由和光猫就是要LAN口相连么?没错,但那是指的配置完成后的连接方式。

在设备出厂、或者刷了新固件后,说明书或文档上都会写清楚当前固件默认配置的IP。例如 R66s 刷的 Lean 固件默认 IP 就是 192.168.100.1。这个配置的意思是,当前设备的 LAN 口配置的是 192.168.100.1 的静态 IP。

而我这边光猫的网段是 192.168.1.0/24 ,软路由的静态 IP 不在这个网段内。这就导致连接光猫的PC设备和软路由是无法连接的,自然也就访问不到后台了。

错误姿势:软路由WAN口直接接光猫LAN口

既然软路由配置静态IP不行,那是不是直接用 WAN 口和光猫的 LAN 口相连就行了?毕竟 WAN 口的默认配置是 DHCP 协议,肯定可以直接加到光猫的网段中。

理论上说当然可以,但是实际上还是要看固件的配置。因为出于安全考虑,很多固件的默认防火墙配置是只允许从 LAN 口访问后台,不允许从 WAN 口访问。

如果我记得不错的话,iStore OS 默认是允许从 WAN 口访问的,而 Lean 固件默认是不允许从 WAN 口访问的。

正确姿势:软路由LAN口先和电脑直连配置好后再接光猫LAN口

为了避免上面的各种问题,最稳妥的方法还是电脑端直接和光猫LAN口相连(或者通过交换机相连),这样就避免了各种上面的幺蛾子。如果一不小心光猫的静态IP还和光猫的IP冲突了,直接断开光猫即可。

首次连接到软路由后台后,按照旁路由的配置思路,需要在 网络-> 接口 -> LAN 中进行如下配置:

  1. 配置协议为静态地址。
  2. 配置 IPV4 地址为当前光猫网段下的一个未被占用的IP地址。
  3. 配置子网掩码为光猫的掩码。
  4. 配置 IPV4 网关为光猫的 IP 地址。
  5. 配置 DNS 服务器为光猫的 IP 地址。
  6. 关闭 DHCP 开关。

配置完成后,当前页面应当就加载不出来了,这时候将软路由和光猫 LAN-LAN 相连,然后通过这里配置的静态IP就又可访问了。

OpenWrt重要路径

OpenWrt 基于 Linux,但是一些重要的配置和Linux 还是有些区别的。重点要关注下面路径下的文件:

  1. /etc/config 这里记录了各个应用的通用配置。操作这里的文件和在 luci 页面中操作是等价的。
  2. /etc/init.d 这里记录了各个应用的启动命令,类似 service 或是 systemctl 的功能。
  3. /usr/lib/lua/luci/ 这里记录了 luci 的页面信息,用于操作 /etc/config 的配置。

配置 SSR-PLUS

Lean 国际版固件自带,或者直接在软件包下搜索安装下面两个包,配置上自己准备好的机场,就能开心使用了。

luci-app-ssr-plus
luci-i18n-ssr-plus-zh-cn

由于 SSR 会深入影响 DNS 解析,路由转发等基础功能。因此一般来说,SSR可以算是家庭网络的最大不稳定因素。所以这里有必要简单了解下 SSR-PLUS 的工作原理,方便定位网络问题。

单纯的 SSR 其实就是一个基于 libshadowsocks 的加密 socks 代理。不过仅此而已肯定不够,毕竟更重要的问题是“选择哪些流量走代理,哪些流量不走代理“。因此我理解 SSR-PLUS 就是 OpenWrt 下 SSR 结合了 iptables + ipset + dnsmasq 的组合工具。

SSR-PLUS 在启动时会加载两个外部订阅的数据。这些配置可以在 /etc/ssrplus 下看到:

  1. 国内IP列表。里面记录了部署在国内不会被墙的IP网段。
  2. GFW 列表。里面记录了被墙的域名。

国内IP列表比较简单,就是在 ipset 里添加一个 china 的路由规则集,方便后续进行 iptables 设置。而GFW 列表除了设置 ipset 之外,还要进行 DNS 选路。

进行 DNS 选路

众所周知,DNS 是明文报文,无良运营商可以很方便的进行 DNS 污染,导致直接解析到错误 IP,更别提后续的连接了。

一种简单的解决方案是将所有 DNS 请求都走 SSR 的 socks 代理,但这样毕竟效率较低。因此实践中常用的办法就是:

  1. 本地启动一个走 SSR 代理的 DNS 服务。可以用 dns2tcp 或者 dns2socks 之类的工具。通常暴露的是 5335 端口。
  2. 根据预先配置的 GFW 列表,告知本地的 dnsmasq 服务,对 GFW 列表内的域名走加密通道,对GFW列表外的域名走普通通道。SSR-PLUS 对 dnsmasq 的配置可以参见 /tmp/dnsmasq.d/dnsmasq-ssrplus.d

这样就能做到安全的 DNS 了。

实际用起来发现dns总是容易挂。。。这里需要加一个定时监测脚本拉一下:

ps -ef|grep /usr/sbin/dnsmasq |grep -qv grep

dns_alive=$?

if [ $dns_alive -ne 0 ]
then
  echo 'dnsmasq down !!!'
  /etc/init.d/dnsmasq restart
  echo 'dnsmasq restarting !!!'
fi

配置 ipset 规则

我们知道 GFW 列表只记录域名,而在用 iptables 对流量路由转发时只能拿到 IP。因此 dnsmasq 在解析 GFW 后,还会将解析出来的 IP 加入到一个名为 gfwlist 的 ipset 规则。

root@OpenWrt:~# ipset list gfwlist
Name: gfwlist
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 56232
References: 2
Number of entries: 1686
Members:
20.198.162.78
65.21.236.8
142.250.186.54
203.77.190.0
54.148.90.231
....

这样一来,再配合 iptables 的 NAT 的 PREROUTING 设置,就能做到针对 GFW 内的域名进行代理转发:

root@OpenWrt:~# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
SS_SPEC_WAN_AC  tcp  --  anywhere             anywhere             /* _SS_SPEC_RULE_ */
...

Chain SS_SPEC_WAN_AC (2 references)
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set gfwlist dst
...

Chain SS_SPEC_WAN_FW (4 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             0.0.0.0/8           
RETURN     all  --  anywhere             10.0.0.0/8          
RETURN     all  --  anywhere             127.0.0.0/8         
RETURN     all  --  anywhere             169.254.0.0/16      
RETURN     all  --  anywhere             172.16.0.0/12       
RETURN     all  --  anywhere             192.168.0.0/16      
RETURN     all  --  anywhere             0.0.0.224.in-addr.arpa/4 
RETURN     all  --  anywhere             240.0.0.0/4         
REDIRECT   tcp  --  anywhere             anywhere             redir ports 1234

GFW模式和绕过中国大陆IP模式的区别

有了上面的基础,我们就明白了其实这两种模式的区别也很简单。看下两种模式下的 iptables 表就清楚了。

GFW模式

Chain SS_SPEC_WAN_AC (2 references)                 
target     prot opt source               destination                  
RETURN     all  --  anywhere             anywhere             match-set whitelist dst
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set blacklist dst
RETURN     all  --  anywhere             anywhere             match-set bplan src         
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set fplan src    
RETURN     tcp  --  anywhere             36.156.102.177       tcp dpt:!domain              
RETURN     all  --  anywhere             anywhere             match-set china dst         
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set gfwlist dst  
                                                               

简要的工作流程是:

  1. 判断目的地址是否在白名单,如果是则不转发。
  2. 判断目的地址是否在黑名单,如果是则直接转发。
  3. 判断目的地址是否是大陆IP,如果是则不转发。
  4. 判断目的地址是否在GFW列表中,如果是则直接转发。
  5. 最后默认不转发

绕过中国大陆IP模式

Chain SS_SPEC_WAN_AC (2 references)                 
target     prot opt source               destination                     
RETURN     all  --  anywhere             anywhere             match-set whitelist dst
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set blacklist dst
RETURN     all  --  anywhere             anywhere             match-set bplan src         
SS_SPEC_WAN_FW  all  --  anywhere             anywhere             match-set fplan src    
RETURN     tcp  --  anywhere             36.156.102.177       tcp dpt:!domain              
RETURN     all  --  anywhere             anywhere             match-set ss_spec_wan_ac dst
RETURN     all  --  anywhere             anywhere             match-set china dst         
SS_SPEC_WAN_FW  all  --  anywhere             anywhere 

简要的工作流程是:

  1. 判断目的地址是否在白名单,如果是则不转发。
  2. 判断目的地址是否在黑名单,如果是则直接转发。
  3. 判断目的地址是否是大陆IP,如果是则不转发。
  4. 最后默认转发

大白话总结就是:

  1. GFW 列表模式是:默认不翻墙,除非你在GFW列表中配置。
  2. 绕过大陆IP模式是:默认翻墙,除非你在国内。

那么具体家里选哪个更合适呢?我个人建议选 GFW 列表模式。虽然绕过大陆IP模式看起来方便,但是:

  1. 考虑到正常大部分流量还是不希望转发的,任何网站只有在GFW列表中、或者你配置的黑名单中才会翻墙。这样你会明确的知道哪些是翻的,哪些是不翻的。
  2. 中国大陆IP列表其实并不完善,很多运营商会偷摸摸使用一些保留IP作为局域网IP(例如类似 224.0.0.68 这类地址)。这就导致这些局域网IP会被中国大陆IP列表当成是海外IP进行转发。这显然就会导致难以排查的网络问题。(尤其是使用 N2N 之类的 P2P VPN 工具时)

配置 socat

不知道为啥 OpenWrt 自带的端口转发功能总是不能正常 work,尤其是转发到内网的其他 IP 时。这时候就需要 socat 来进行额外的端口转发功能。

安装下面的包即可:

luci-i18n-socat-zh-cn
luci-app-socat

然后就可以在 网络 -> Socat 里愉快的进行端口转发了。

配置 n2n

使用 v3 版的 n2n 需要先更新下 opkg 的源,否则拉不到适配 v3 版本的 luci-app 。虽然可以直接改 /etc/config/n2n 配置文件,不过毕竟不太优雅。

不知道为啥固件自带的源长这样,luci 的版本都跟其他的不一样。。。

src/gz openwrt_base https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/base
src/gz openwrt_luci src/gz openwrt_luci https://downloads.immortalwrt.org/releases/packages-18.06-k5.4/aarch64_generic/luci
src/gz openwrt_packages https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/packages
src/gz openwrt_routing https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/routing
src/gz openwrt_telephony https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/telephony

改成一样即可:

src/gz openwrt_base https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/base
src/gz openwrt_luci https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/luci
src/gz openwrt_packages https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/packages
src/gz openwrt_routing https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/routing
src/gz openwrt_telephony https://downloads.immortalwrt.org/releases/21.02.1/packages/aarch64_generic/telephony

配置好 n2n 客户端后,再在服务端配置好 nginx,挂上 ssl 域名 ,就能从远端访问家里的 OpenWrt 配置后台了。

当然,由于有些 luci 组件是需要额外暴露端口的,因此直挂 80 端口的 nginx 的话,实时监控、tty终端之类的功能还是没法用的。

运行一段时间后发现 n2n 的客户端 edge 经常时不时的挂掉,logread 看了下日志:

# logread |grep n2n
Thu Mar 30 19:24:48 2023 daemon.info n2n-edge[21183]: 30/Mar/2023 11:24:48 [n2n.c:38] ERROR: Unable to create socket [No file descriptors available][-1]
Thu Mar 30 19:24:48 2023 daemon.info n2n-edge[21183]: 30/Mar/2023 11:24:48 [edge_utils.c:273] ERROR: failed to bind main UDP port 0
...

看起来似乎是进程打开的最大句柄数超过了上限,确认了一下发现 ulimit -a 里看到的限制是 1024 ,实际 ls -lA /proc/{pid}/fd|wc -l  看到的正好也是 1024 (ls 的 -lA 参数忽略了 . 目录和 .. 目录,如果直接 ls -la 则是 1026)。。。

解决方式是改 ulimit 增大全局配置,或者直接修改 /etc/init.d/n2n 配置文件,增加进程的配额。而我选择后者(参考 openwrt 配置):

  procd_set_param limits core="unlimited"
  procd_set_param limits nofile="10240"
  procd_set_param limits nproc="10240"

(更新)发现上面的配置没用, cat /proc/{pid}/limits 发现 nofile 的配置并没有生效。于是自己写了一个脚本,当 fd 超过限制就自动重启下 n2n,放在 cron 里定期执行:

n2n_pid=`ps -ef|grep /usr/bin/n2n-edge |grep -v grep |awk '{print $1}'`

if [ ! $n2n_pid ]
then 
  echo 'n2n not started'
  exit 1
fi

fd_cnt=`ls /proc/${n2n_pid}/fd |wc -l`

if [ ${fd_cnt} -ge 1024 ]
then
  /etc/init.d/n2n restart
fi

配置 Dropbear

Dropbear 可以理解是 OpenWrt 下的 sshd 。为了安全起见,dropbear 默认只对 lan 口过来的请求开放 ssh 连接。因此在配置好 n2n 之后,也是无法直接访问这个服务的。这里需要先关闭下 dropbear 对 lan 口的绑定:

root@OpenWrt:/etc/config# cat /etc/config/dropbear 
config dropbear
        option PasswordAuth 'on'
        option RootPasswordAuth 'on'
        option Port         '22'
#        option Interface    'lan'
#       option BannerFile   '/etc/banner

配置好后 restart 即可生效。

root@OpenWrt:/etc/config# /etc/init.d/dropbear restart

配置各个客户端

软路由配置好了后先不要急着连接设备。建议先重启几次路由器,确保配置正常生效,且重启不丢失。确认完成后,各个需要连接的客户端再手动配置下:

  1. 关闭 DHCP,IP 地址设置为原先自动分配的IP即可。
  2. 将网关/路由器设置为软路由IP。
  3. 将子网掩码设置为和主路由一致。
  4. 将 DNS 设置为软路由IP。

正常情况下,配置好后即可感受科学的魅力,不过偶尔也可能出现一些奇怪的坑。此时可以先尝试:

  1. 关闭 IPV6。SSR 不支持 IPV6 ,如果一不小心走了 IPV6,则基本上是翻不出去的。
  2. 重启设备。像 IPhone 这类的设备似乎配置完后要重启一下,否则容易报诸如 SSL Error 之类的错。
❌
❌