华硕路由器官方固件开机自动运行脚本方法

本教程重在寻找过程,如果你在意最终结果,请直接看本文最后一段脚本。
  
在几天前,我看到了这篇文章《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://someonewhocares.org/hosts/zero/hosts
http://pgl.yoyo.org/adservers/se ... &mimetype=plaintext
不过原文中的命令不适用于我,我首先需要做的是:找一个命令把这些链接中的内容写入到路由器的 hosts 中。
  
经过了一番寻找,我找到了这两篇文章《分享一个OpenWRT路由器的自动更新hosts方法,无需脚本》[5] 和《路由器自动修改hosts脚本》[6],这两篇文章都是国人写的,里面命令对我十分有用。
借助《wget 指令用法與教學》[7] 对命令进行了简单的修改,我得到了可以用于路由器更新 hosts 的命令:

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

复制代码

并且将其制作为脚本:

  1. #!/bin/sh
  2. wget -q  "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 修改后不能生效的问题:

  1. killall -SIGHUP dnsmasq

复制代码

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

  1. #!/bin/sh
  2. wget -q "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts
  3. sleep 30
  4. 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]

  1. 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:
  1. i=0
  2. while [ $i -le 20 ]; do
  3.       success_start_service=`nvram get success_start_service`
  4.       if [ "$success_start_service" == "1" ]; then
  5.               break
  6.       fi
  7.       i=$(($i+1))
  8.       echo "autorun APP: wait $i seconds...";
  9.       sleep 1
  10. done
复制代码

大意为

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


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

  1. #!/bin/sh
  2. i=0
  3. while [ $i -le 20 ]; do
  4.       success_start_service=`nvram get success_start_service`
  5.       if [ "$success_start_service" == "1" ]; then
  6.               break
  7.       fi
  8.       i=$(($i+1))
  9.       echo "autorun APP: wait $i seconds...";
  10.       sleep 1
  11. done
  12. wget -q  "http://someonewhocares.org/hosts/zero/hosts" "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext" -O /etc/hosts
  13. sleep 30
  14. 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 里面应该至少包含以下内容:

  1. #!/bin/sh
  2. i=0
  3. while [ $i -le 20 ]; do
  4.       success_start_service=`nvram get success_start_service`
  5.       if [ "$success_start_service" == "1" ]; then
  6.               break
  7.       fi
  8.       i=$(($i+1))
  9.       echo "autorun APP: wait $i seconds...";
  10.       sleep 1
  11. done
  12. #从下方开始你的脚本

复制代码

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

  1. #!/bin/sh
  2. i=0
  3. while [ $i -le 20 ]; do
  4.       success_start_service=`nvram get success_start_service`
  5.       if [ "$success_start_service" == "1" ]; then
  6.               break
  7.       fi
  8.       i=$(($i+1))
  9.       echo "autorun APP: wait $i seconds...";
  10.       sleep 1
  11. done
  12. /opt/test1
  13. sleep 1
  14. /opt/test2
  15. sleep 1
  16. /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 Routers(将脚本运行在华硕路由器上 英文)
[10] 与 @Jack- 讨论开机脚本的问题
[11] 上海电信4K盒子+华硕路由器原厂固件/R7000实现拨号

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

你可能感兴趣的:(华硕路由器官方固件开机自动运行脚本方法)