【转载】[教程] 华硕路由器官方固件开机自动运行脚本方法

Asuswrt-Merlin (梅林)固件我以前玩过、国人改版的梅林我也玩过,因为没有使用代理隧道的需求,所以很早之前我就不使用第三方固件了。在我使用官方固件的这些时期,我一直很困惑,怎样才能像之前一样运行脚本?当然,我可以使用 telnet 或者 SSH 执行命令,但太费事了,而且没有办法按照我的需求开机自动运行,直到几天前我找到了方法,现在将我的经验分享出来。
以下教程以 “华硕路由器原厂固件开机后自动修改 hosts 文件” 为例。

你需要准备:一个 U盘(移动硬盘也可)一台路由器一台电脑

此教程当然也适用于 Asuswrt-Merlin 固件,Asuswrt-Merlin 拥有断电后仍可保留数据的 JFFS 分区,但是 Asuswrt-Merlin 在 JFFS 百科 中这样写道:

I do not recommend doing frequent writes to this area, as it will prematurely wear out the flash chip. This is a good place to put files that are written once like scripts or kernel modules, or that rarely get written to. Do not put files that get constantly written to (such as high activity logfiles) – store these on a USB disk instead. Replacing a worn out USB flash disk is much cheaper than replacing the whole router if flash sectors get worn out – they have a limited number of write cycles.

大意是:

我不建议经常向 JFFS 分区写入数据,这会使路由器的闪存过早报废,JFFS 分区适合存入如脚本或内核模块等写入量很小的文件,如果你要不断地存储数据(比如大量日志文件)我建议存放到 U盘 上,虽然两者写入量都是有限的,但更换 U盘 要比更换路由器闪存芯片成本更低。

所以,你可以用此教程将需要自启动的脚本等文件统统保存到 U盘 上,对于使用 Asuswrt-Merlin 固件的玩家来说,这是对路由器的一种保护。

在教程开始之前你需要知道:我是一个小白,不懂得如何编写脚本、甚至看不懂脚本,我只会拿别人现成的脚本放到路由器中。为了实现这篇教程的核心思想 “华硕路由器官方固件开机自动运行脚本” 我曾四处寻求帮助,我很高兴通过各种类型的帮助最终实现了目标,没有这些帮助就没有这篇教程,这篇教程将以叙事的形式展现,我将会在本篇教程中注明每一个帮助信息。

本教程重在寻找过程,如果你在意最终结果,请直接看本文最后一段脚本。

在几天前,我看到了这篇文章《ac68等arm迅雷、aria2安装小白教程及官固自启动插件教程》[1],标题中的 “官固自启动” 让我非常感兴趣,通过这篇文章我了解到:华硕路由器的 Download Master(下载大师)功能保存在 U 盘上,而华硕官方固件(或 Asuswrt-Merlin)可以运行 U 盘上的脚本,我们也可以将自己的脚本放在 U 盘上实现开机自动运行。
具体是如何实现的?
我向 52asus 的一位管理者 Master 寻求帮助,收到了如下回复

你尝试一下将任意脚本放到/opt/etc/init.d/ 中,并且以 S 开头

相对于 U 盘,是放到了 asusware.arm/etc/init.d/ 目录下
他建议我参考这篇文章《RT-AC66UB1 开机自动执行脚本》[2],这篇文章初期对我的帮助价值非常大,很贴近最终答案,不过由于后面有更好地解决方法,这篇文章不会被用于本教程。

于是,我就想到,我之前在 Asuswrt-Merlin 固件时用到的屏蔽广告脚本《AdBlocking with combined hosts file》[3] 能否在我当前官方固件上运行?这个脚本主要是基于修改 hosts 文件实现,官方固件也可以修改 hosts,但是每次开机后 hosts 文件都会被刷新重置 [4],所有保存的信息会被清空。那么我能否利用上方发现的自启动脚本方法,在每次开机清空后再重新写入新的信息到 hosts 文件?答案是可行的。

仔细分析《AdBlocking with combined hosts file》文章,我看到了屏蔽广告的 hosts 来源,分别是:
http://winhelp2002.mvps.org/hosts.txt
http://someonewhocares.org/hosts/zero/hosts
http://pgl.yoyo.org/adservers/se … &mimetype=plaintext
不过原文中的命令不适用于我,我首先需要做的是:找一个命令把这些链接中的内容写入到路由器的 hosts 中。

经过了一番寻找,我找到了这两篇文章《分享一个OpenWRT路由器的自动更新hosts方法,无需脚本》[5] 和《路由器自动修改hosts脚本》[6],这两篇文章都是国人写的,里面命令对我十分有用。
借助《wget 指令用法與教學》[7] 对命令进行了简单的修改,我得到了可以用于路由器更新 hosts 的命令:

wget -q "http://winhelp2002.mvps.org/hosts.txt" "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts

并且将其制作为脚本:

#!/bin/sh
wget -q "http://winhelp2002.mvps.org/hosts.txt" "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts

 

命令运行成功,在路由器中 ping 相应网址也得到了正确反馈,但我很快发现,为何我的电脑仍能看到广告?我在电脑中 ping 这些网站发现并没有被屏蔽。于是我开始找原因,在上面那些包含命令的文章中,我注意到了几个关键的命令 service restart_dnsmasq 和 /etc/init.d/dnsmasq restart 这些命令都是用来重启 dnsmasq 的,似乎必须重启后才能对客户端生效,前一个命令重启后会导致 hosts 如同开机般被清空,后者则不适用于华硕路由器。我又重新开始寻找新的命令。

在和《RT-AC66UB1 开机自动执行脚本》作者 右手边 交流中,他为我提供了一个新的命令,并发布了一篇教程《如何更改华硕路由器的 hosts》[8],这个新的命令完美地解决了 hosts 修改后不能生效的问题:

killall -SIGHUP dnsmasq

 

既然有了这个命令,那么就把它加入脚本

#!/bin/sh

wget -q "http://winhelp2002.mvps.org/hosts.txt" "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts

sleep 30

killall -SIGHUP dnsmasq

实践证明脚本完美运行。既然可以运行,那么让我来将其改造为开机启动。在本文开头提到的开机启动方法固然可以,但是过于复杂,因为需要基于各种库,如果用不到 Download Master,那些库就没有必要,毕竟那么多的库会拖慢开机时间。

因此我开始寻找一个更好地方法,在寻找中我看到了一个新的文章《Hacking Functionality into ASUSWRT Routers》[9] 其中这样写道:

When a USB storage device is inserted into the router’s USB port, the rc system daemon mounts the partition and checks for the existence of an asusware/.asusrouter script on the mount point. If it exists, the asusware folder is then symlinked to /tmp/opt (and also /opt) and the script is executed. Since this is all open source, you can find the relevant code in the mount_partition function in release/src/router/rc/usb.c.

大意为:

当 U 盘插入路由器后,rc 系统守护进程将挂载 U 盘,并检查 U 盘 asusware 文件夹下是否存在名为 .asusrouter 的脚本文件,如果存在将会把 asusware 文件夹链接为 /tmp/opt(和 /opt),并且运行脚本。因为是开源固件,可以在源代码 release/src/router/rc/usb.c 的 mount_partition 函数中找到相关信息。

大家明白了吗?这就是为什么之前脚本要放在 asusware.arm/etc/init.d/ 里面,因为 opt/etc/init.d/ 是启动目录,开机后会运行 /init.d/ 目录下所有的脚本。但是会首先运行 asusware.arm/.asusrouter 这个脚本。

.asusrouter 这个脚本后来了解到主要是用来启动各种库的命令 [10],而我不需要 Download Master 也用不到这些库,直接清空 .asusrouter 文件,将自己的脚本写进去即可。《Hacking Functionality into ASUSWRT Routers》文章中也写道:

Put the commands you wish to execute in asusware/.asusrouter on your USB storage device. Like any shell script, make sure it has #!/bin/sh as its first line and that the file uses UNIX line endings. The filesystem can be anything supported by the kernel – ext2, ext3 or fat. If you are using a filesystem that implements Linux permissions (such as ext2 or ext3), be sure to set the script as executable.

大意为:

将你的命令保存到 U盘 asusware 目录下的 .asusrouter 文件中,和任何 shell 脚本一样,确保脚本第一行内容为 #!/bin/sh,并且以 UNIX 作为换行符,内核支持 ext2、ext3 或 fat 格式的 U 盘,如果使用 Linux 的 ext2 或 ext3 文件系统,请确保脚本拥有执行权限。

他写的这篇文章文件夹目录是不完全正确的,因为 ARM CPU 的路由器文件夹目录是 asusware.arm,一共有四种对应不同架构 CPU 的目录,分别是:asusware、asusware.arm、asusware.big 和 asusware.mipsbig,要确定你的路由器是哪种请在 telnet 下输入命令 [11]

nvram get apps_install_folder

 

接下来需要注意的是 U 盘不一定是  ext2、ext3 或 fat 格式,经过我的测试 NTFS 和 FAT32 也可以。最重要的是 FAT、FAT32 和 NTFS 这三种格式不需要修改权限,因此我推荐使用这三种格式。

继续看《Hacking Functionality into ASUSWRT Routers》文章

One caveat when running network programs (like DHCP forwarder or mDNS repeater) is that you need to wait until everything has been initialized. ASUS does that by polling the success_start_service NVRAM variable with this bash snippet:

i=0

while [ $i -le 20 ]; do

      success_start_service=`nvram get success_start_service`

      if [ "$success_start_service" == "1" ]; then

              break

      fi

      i=$(($i+1))

      echo "autorun APP: wait $i seconds...";

      sleep 1

done

 

大意是:

运行和网络有关的脚本,需要等待路由器所有程序初始化完成。因此华硕使用如下命令保证这一点。
这段命令大意是:不断查询程序是否初始化完成,如果没有完成就等待,如果完成了就运行接下来的命令。

由于 hosts 是和网络有关的脚本,因此我必须等待所有程序初始化完成。

所以,最终的开机修改 hosts 脚本为:

#!/bin/sh

i=0

while [ $i -le 20 ]; do

      success_start_service=`nvram get success_start_service`

      if [ "$success_start_service" == "1" ]; then

              break

      fi

      i=$(($i+1))

      echo "autorun APP: wait $i seconds...";

      sleep 1

done

wget -q "http://winhelp2002.mvps.org/hosts.txt" "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts

sleep 30

killall -SIGHUP dnsmasq

将这段脚本保存为 .asusrouter 文件,然后放到 U 盘的 asusware 或者 asusware.arm 或者 asusware.big 或者 asusware.mipsbig 文件夹中,我的路由器则是放到 asusware.arm 目录中。

好了,这就可以开机运行了

对于你,你也可以将任何 shell 脚本写在 .asusrouter 里面(以 UNIX 作为换行符),并且保存在 U 盘上 asusware 或者 asusware.arm 或者 asusware.big 或者 asusware.mipsbig 文件夹中,具体是哪一个文件夹,上方有查询方法。
我建议 .asusrouter 里面应该至少包含以下内容:

#!/bin/sh

i=0

while [ $i -le 20 ]; do

      success_start_service=`nvram get success_start_service`

      if [ "$success_start_service" == "1" ]; then

              break

      fi

      i=$(($i+1))

      echo "autorun APP: wait $i seconds...";

      sleep 1

done

#从下方开始你的脚本

 

如果你有多个脚本,我建议将多个脚本独立保存为随意文件名,然后放入 asusware 或者 asusware.arm 或者 asusware.big 或者 asusware.mipsbig 文件夹中,在 .asusrouter 文件里面直接写一段代码引导到你的脚本,例如我有名为 test1、test2 和 test3 脚本保存在 U 盘的 asusware.arm 文件夹里面,我想要他们几乎同时启动,我需要这样写:

#!/bin/sh

i=0

while [ $i -le 20 ]; do

      success_start_service=`nvram get success_start_service`

      if [ "$success_start_service" == "1" ]; then

              break

      fi

      i=$(($i+1))

      echo "autorun APP: wait $i seconds...";

      sleep 1

done

/opt/test1

sleep 1

/opt/test2

sleep 1

/opt/test3

如果你不需要同时运行这些脚本,而是上一个脚本运行结束、再运行下一个,你只要将 test1 写在启动命令里面,然后编辑 test1 文件,在最后一行加入 /opt/test2 启动 test2,test2 脚本最后一行加入 /opt/test3 启动 test3,如同多米诺骨牌一样。

特别感谢:
来自 koolshare 的 konglang_616,来自 52asus 的 Master 和 右手边

参考资料:
[1] ac68等arm迅雷、aria2安装小白教程及官固自启动插件教程
[2] RT-AC66UB1 开机自动执行脚本
[3] AdBlocking with combined hosts file(利用 hosts 文件过滤广告 英文)
[4] 請問RT-N16以及N66U的hosts修改
[5] 分享一个OpenWRT路由器的自动更新hosts方法,无需脚本
[6] 路由器自动修改hosts脚本
[7] wget 指令用法與教學
[8] 如何更改华硕路由器的 hosts
[9] Hacking Functionality into ASUSWRT Router(将脚本运行在华硕路由器上 英文)
[10] 与 @Jack- 讨论开机脚本的问题
[11] 上海电信4K盒子+华硕路由器原厂固件/R7000实现拨号

其他资料:
[12] Asuswrt-Merlin 開機時未執行 init.d 腳本的問題
[13] User scripts · RMerl/asuswrt-merlin Wiki(用户脚本 梅林百科 英文)
[14] ASUSWRT原廠固件安裝 entware

转载自http://www.52asus.com/thread-3692-1-1.html

© 如果需要以学习目的转载、复制这篇教程,请出于尊重保留所有的段落,以及每一个注明信息。此篇教程禁止用于任何商业形式。

发表回复