光猫HG6145D2改造

起因

在搬家后迁移联通的宽带,装维师傅给换了个光猫,换成了HG6145D2,然后之前好使的IPv6外网访问就失效了。

分析

查看路由器,IPv6地址可以正常分配。之后进入光猫后台,尝试一番后发现其防火墙功能残缺,无法像之前一样通过单独关闭IPv6防火墙或调整防火墙等级来实现IPv6外网访问。通过一番检索,了解到该款光猫可以通过指定网址来开启telnet,然后通过ip6tables命令来控制IPv6防火墙,从而实现IPv6外网访问。但是在之后的测试中却发现,光猫固件做的防范比较严格,没有找到可以利用的开机启动入口来实现控制固化。没办法,最终决定通过定时执行外部脚本来解决该问题。

处理

将操作步骤写成Python脚本,并通过我路由器上的supervisor进行托管执行。

关键代码如下:

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
def main_task():
timeout = 10
while True:
try:
r = requests.get("http://192.168.1.1/telnet?enable=1&key=112233445566")
if r.status_code != 200:
raise Exception("status_code is not 200, it is {}".format(r.status_code))
with telnetlib.Telnet("192.168.1.1") as telnet:
telnet.read_until(b"login: ", timeout)
telnet.write(b"admin\n")
telnet.read_until(b"Password: ", timeout)
telnet.write(b"Fh@445566\n")
telnet.write(b"rm -f /var/tmp.sh\n")
telnet.write(b"echo '#!/bin/sh' >> /var/tmp.sh\n")
telnet.write(b"echo 'ip6tables -vnL | grep FORWARD_CUSTOM' >> /var/tmp.sh\n")
telnet.write(b"echo 'if [ $? != 0 ]; then' >> /var/tmp.sh\n")
telnet.write(b"echo ' ip6tables -N FORWARD_CUSTOM' >> /var/tmp.sh\n")
telnet.write(b"echo ' ip6tables -A FORWARD -j FORWARD_CUSTOM' >> /var/tmp.sh\n")
telnet.write(b"echo ' ip6tables -A FORWARD_CUSTOM -p icmpv6 --icmpv6-type echo-request -j ACCEPT' >> /var/tmp.sh\n")
# 由于offload的原因,该条规则不用写
# telnet.write(b"echo ' ip6tables -A FORWARD_CUSTOM -p icmpv6 --icmpv6-type echo-reply -j ACCEPT' >> /var/tmp.sh\n")
telnet.write(b"echo ' ip6tables -A FORWARD_CUSTOM -p udp --dport 10000 -j ACCEPT' >> /var/tmp.sh\n")
# 由于offload的原因,该条规则不用写
# telnet.write(b"echo ' ip6tables -A FORWARD_CUSTOM -p udp --sport 10000 -j ACCEPT' >> /var/tmp.sh\n")
telnet.write(b"echo ' ip6tables -A FORWARD -j FORWARD_CUSTOM' >> /var/tmp.sh\n")
telnet.write(b"echo 'fi' >> /var/tmp.sh\n")
telnet.write(b"chmod +x /var/tmp.sh\n")
telnet.write(b"/var/tmp.sh\n")
telnet.write(b"rm -f /var/tmp.sh\n")
telnet.write(b"exit\n")
result = telnet.read_all()
_LOGGER.info("success, wait 30 min for next")
time.sleep(60*30)
except Exception as e:
_LOGGER.exception(e)
time.sleep(60*1)

该代码适配时请注意如下几点:

  1. 光猫地址192.168.1.1请修改为自己的光猫地址
  2. 开启telnet的key为自己的光猫MAC地址
  3. telnet密码为自己的光猫MAC地址后6位

结果

通过外部控制脚本,实现了IPv6的外网访问,最多会在光猫重启后短暂的失败一段时间,但基本不影响正常使用。后续若能找到光猫上可用的开机启动入口,可以在光猫上就近部署脚本,进而解除外部依赖,缩短不可用时间。

参考

  1. 恩山无线论坛讨论贴
  2. Python的Telnet相关文档说明
  3. ip6tables命令说明