0%

merlin-梅林路由器自动切换网关

缘由

目前家里是使用AC86U+N1搭建上网环境,N1用来做辅助网关。如果手动设置的话,如果N1挂掉了,或者无法上网,就导致AC86U手动设置的N1网关无效,从而导致AC86U无法上网了。

目的:如果家人取下N1的lan,就自动切换为AC86U为网关,那么就能保证N1出问题的时候,家人拔下N1就可以恢复上网了。

我家用的网络拓扑图如下:
AC86U.005

于是寻找一些论坛,如恩山,koolshare,都没有自动切换网关的脚本,所以就自己写了一下,我也大概看了一下asuswrt-merlin.ng里面的Service是有哪些命令,并且发现路由是通过nvram命令进行数据储存的用户的路由存储配置。
脚本已经使用几个月了,功能比较稳,可以满足需求

脚本文件

现在先给出脚本实现和配置auto_switch_gateway.sh,可以根据自己的情况修改ip参数,up_gateway是标记AC86U的WAN是否连上了,如果是没有跟我一样的网络拓扑结构,而是路由器拨号上网的,可以把up_gateway修改成公共DNS网关。如,223.5.5.5或者114.114.114.114

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
#!/bin/bash

default_gateway='192.168.50.1'
auxiliary_gateway='192.168.50.2'

up_gateway='192.168.1.1'

check_ip_available(){
ping -c 3 $1 | grep packets | awk '{print $4}'
}

# If the gateway of the up close, the network is completely unusable

res=`check_ip_available $up_gateway`
echo $res
if [ $((res)) -eq 0 ]; then
echo "up_gateway unusable"
exit 1
fi


cur_gateway=`/bin/nvram get dhcp_gateway_x` # get current gateway


if [ "$cur_gateway" = "$default_gateway" ]; then
echo "cur is default_gateway"
res=`check_ip_available $auxiliary_gateway`
if [ $(($res)) -eq 0 ]; then
echo "d-exit"
exit 1
fi
echo "switch to auxiliary"
# to switch
/bin/nvram set dhcp_gateway_x=$auxiliary_gateway
/bin/nvram set dhcp_dns1_x=$auxiliary_gateway
/bin/nvram set dhcp_dns2_x=""
/bin/nvram commit

/sbin/rc rc_service restart_net_and_phy
exit 0
fi


if [ "$cur_gateway" = "$auxiliary_gateway" ]; then
echo "cur is auxiliary_gateway"
res=`check_ip_available $auxiliary_gateway`
if [ $(($res)) -gt 0 ]; then
echo "a-exit"
exit 1
fi
echo "switch to default"
# to switch
/bin/nvram set dhcp_gateway_x=$default_gateway
/bin/nvram set dhcp_dns1_x=119.29.29.29
/bin/nvram set dhcp_dns2_x=223.5.5.5
/bin/nvram commit

/sbin/rc rc_service restart_net_and_phy
exit 0
fi

echo "nothing change"

/sbin/rc rc_service restart_net_and_phy,这句命令,其实就是路由器修改本地网关后,会触发的命令。所以这个命令,和网页手动触发效果是一样的LAN代码。这样不用调用reboot命令重启路由器

AC86U.003

可是我后面发现了一个问题,上面仅仅是通过终端运行脚本,使用ping命令来判断网络的情况和网关的情况,并且优先切换到切换到辅助网关上。这脚本仅仅是自己手动运行执行来检测网络情况的,所以我需要一个自动运行这个检测脚本的脚本

梅林init-start路由启动钩子

如果你直接在路由添加crontab定时任务,重启就会被清空,而/jffs/scripts/init-start会在路由器开机时执行

所以我们就可以通过在init-start 添加任务到crontab,进行定时触发我们的网络情况监测

我做了个延迟添加网络监听任务到crontab任务脚本create_crontab_auto_switch_gateway.sh

意思是init-start触发create_crontab_auto_switch_gateway.sh,然后create_crontab_auto_switch_gateway.sh每秒判断AC86U的WAN外网是否可以ping通,如果可以ping通就添加上面的auto_switch_gateway.sh到crontab中。

为什么要这样处理呢?因为init-start的执行时间不确定,而且是比较早的。所以我需要等待到网络好了,再添加网络监测,想要达到类似Systemd 的Service 的 After=network.target的作用

下面代码需要需改 /var/spool/cron/crontabs/xxx成 对应的参数,下面示例,xxx是我的AC86U路由器登陆账号,192.168.1.1是我AC86U的WAN连接的广电盒子,如果跟我的网络拓扑图不一样,是路由器直接拨号上网,可以修改成114.114.114.114

reate_crontab_auto_switch_gateway.sh代码如下,需要简单修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

while true
do
sleep 1;
ping -c 1 192.168.1.1 > /dev/null #判断路由器的WAN是否连接上了

if [ $? -ne 0 ]; then
continue
fi
echo "* * * * * /bin/bash /jffs/scripts/auto_switch_gateway.sh" >> /var/spool/cron/crontabs/xxx# 这里需要把XXX改成你的路由账号名
break

done

把上面两个脚本都放在/jffs/scripts/目录下,然后我们看下init-start配置

1
2
#!/bin/sh
/bin/bash /jffs/scripts/create_crontab_auto_switch_gateway.sh

如上,就配置好了网关定时任务切换

其它优化

如果你遇到梅林路由AC86U网页后台管理打不开,但是路由还能上网,可以添加这个定时任务到init-start,每天4点重启http进程,如下:

1
echo '0 4 * * * service restart_httpd' >> /var/spool/cron/crontabs/xxx

如果你和我一样,是用广电盒子,广电盒子上网重启后比较坑,需要开广电的U点盒子开电视后,才能上网的。

一开始我就尝试抓包摸索,到底是什么东西触发让U点盒子可以激活广电盒子上网的,后来发现,只要直接访问广电盒子的网关服务器管理页面,就可以不需要开启广电U点盒子来让广电盒子上网了,所以我就添加了个启动路由器的时候定时发出个curl。

1
echo '* * * * * /usr/sbin/curl http://192.168.1.1/cgi-bin/luci' >> /var/spool/cron/crontabs/xxx

所以,我的init-start是这样的

1
2
3
4
#!/bin/sh
/bin/bash /jffs/scripts/create_crontab_auto_switch_gateway.sh
echo '0 4 * * * service restart_httpd' >> /var/spool/cron/crontabs/xxx
echo '* * * * * /usr/sbin/curl http://192.168.1.1/cgi-bin/luci' >> /var/spool/cron/crontabs/xxx

总结

auto_switch_gateway.sh 是用来每分钟检测网络状况,并且进行网关切换的(而网关切换一般需要35-40秒,就像你在路由管页修改网关时,点击提交那样需要的时间,所以需要设置为每分钟检测,这样保守点)

然后路由器是init-start开机时候执行的,因为直接在crontab添加,重启后脚本就被清空了。所以需要在这里添加。

由于init-start是比较早执行的,可能那时候路由器的网络相关功能还没初始好,所以我们需要延迟一下,每秒判断AC86U的WAN是否连接上了,才添加auto_switch_gateway.sh 任务到 crontab

有可能你会疑惑service和rc_service。一开始我发现service.c有些命令好像不能执行,但是现在测试又可以了,/sbin/rc rc_service反而可以运行想要的命令,也可以找到很多命令。我没有深入了解它们的真实区别。而且可以看到rc执行main是往某个进程发送命令的 ,这里可以找到其它命令administration.cservice.crc.c

论坛推荐

有些资料也是从论坛搜来的,感谢互联网

Snbforums

恩山

Koolshare

请我喝杯咖啡~

欢迎加我微信交流~