1. 背景
IPv6相比IPv4的一大优势是IP地址空间充足。以笔者的中国移动宽带为例,光猫可以从运营商处获得2409开头的/64公网网段,连接至光猫的设备可自动获得公网IPv6地址:

但处于安全考虑,光猫的IPv6防火墙会默认禁用所有入站连接,导致其它公网设备无法直连光猫防火墙内部的设备:

幸运的是,笔者使用的中国移动H2-2光猫在网上有大量使用教程,可以通过配置IPv6防火墙的方式解决这个问题。
2. 开启光猫telnet功能
- 用普通账号登录光猫管理后台(http://192.168.1.1/),可以看到非常简陋的配置界面。 -   
 
- 此时可以手动跳转至telnet设置界面(http://192.168.1.1/getpage.gch?pid=1002&nextpage=tele_sec_tserver_t.gch),开启光猫的telnet功能。 -   
 
- 在Chrome浏览器控制台中运行- document.getElementById("Frm_TSPassword").type = "text"命令可显示telnet密码。
 - 
- 不过好像所有的H2-2光猫telnet密码都是aDm8H%MdA,且无法通过这个页面更改
  
 
- 在本机命令行中运行telnet命令即可登录至光猫,并通过su命令获取root权限: | 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | ~ telnet 192.168.1.1Trying 192.168.1.1...
 Connected to 192.168.1.1.
 Escape character is '^]'.
 
 Login: CMCCAdmin
 Password:
 ~ $ su
 Password:
 / #
 
 |  
 
3. 自动登录telnet脚本
考虑到telnet登录比较繁琐,所以笔者编写了一个expect脚本,用于自动登录光猫:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 |  ~ cat ~/scripts/telnet_modem#!/usr/bin/env expect
 set timeout 5
 set host "192.168.1.1"
 set user "CMCCAdmin"
 set pwd "aDm8H%MdA"
 
 spawn telnet $host
 expect "Login: "
 send "$user\n"
 sleep 0.1
 expect "Password: "
 send "$pwd\n"
 sleep 0.1
 expect "~ $ "
 send "su\n"
 sleep 0.1
 expect "Password: "
 send "$pwd\n"
 sleep 0.1
 interact
 
 | 
运行该脚本后即可登录光猫并获取root权限。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 |  ~ ~/scripts/telnet_modemspawn telnet 192.168.1.1
 Trying 192.168.1.1...
 Connected to 192.168.1.1.
 Escape character is '^]'.
 
 Login: CMCCAdmin
 Password:
 ~ $ su
 Password:
 / #
 
 | 
4. 配置IPv6防火墙
光猫的IPv6防火墙可通过ip6tables命令直接配置。登录光猫后运行如下命令:
| 12
 
 | ip6tables -I FORWARD -p tcp -m multiport --dports 10000:10009,12345 -j ACCEPTip6tables -I FORWARD -p udp -m multiport --dports 10000:10009,12345 -j ACCEPT
 
 | 
即可让光猫转发目标端口为10000~10009、12345的tcp/udp流量。

5. 持久化IPv6防火墙
光猫重启后以上设置的防火墙规则会被清除,其它文章提到的持久化方式笔者没能复现。所以笔者编写了一个Python脚本用于配置防火墙端口,并通过crontab定期执行来实现持久化地效果:
| 12
 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
 
 | import telnetlib
 from datetime import datetime
 
 need_forward = {'10000:10009', '12345'}
 host, timeout = '192.168.1.1', 3
 user, pwd = 'CMCCAdmin', 'aDm8H%MdA'
 
 print(str(datetime.now())[:19])
 
 tn = telnetlib.Telnet(host, timeout=timeout)
 def exec(expect: str, command: str) -> str:
 expectBytes = expect.encode('utf-8')
 content = tn.read_until(expectBytes, timeout=timeout)
 if not content.endswith(expectBytes):
 raise ValueError('expect {}, got {}'.format(repr(expect), repr(content.decode('utf-8'))))
 tn.write(command.encode('utf-8') + b'\n')
 
 return content.decode('utf-8')
 exec('Login: ', user)
 exec('Password: ', pwd)
 exec('~ $ ', 'su')
 exec('Password: ', pwd)
 
 
 def forwarded_ports() -> set:
 exec('/ # ', 'ip6tables -L FORWARD')
 forwarded = set()
 for line in exec('/ # ', '').split('\n'):
 line = line.strip()
 if not line.startswith('ACCEPT'):
 continue
 forwarded.update(line.split()[-1].split(','))
 return forwarded
 forwarded = forwarded_ports()
 
 
 
 new_ports = need_forward - forwarded
 if new_ports:
 ports_str = ','.join(new_ports)
 exec('/ # ', 'ip6tables -I FORWARD -p tcp -m multiport --dports {} -j ACCEPT'.format(ports_str))
 exec('/ # ', 'ip6tables -I FORWARD -p udp -m multiport --dports {} -j ACCEPT'.format(ports_str))
 forwarded = forwarded_ports()
 print('forwarded: ', forwarded)
 
 tn.close()
 
 | 
| 1
 | */1 * * * * /home/worker/scripts/cron/router_ip6tables.py >> ~/ram/router_ip6tables.log 2>&1
 | 
6. 后记
网上其它文章详细介绍了如何获取光猫宽带拨号/超级管理员账号密码、如何桥接路由器。但对于可以屏蔽光猫IP地址自动分配、配置光猫防火墙的笔者来说,桥接已经没有什么吸引力了。另外笔者发现,即使通过超级管理员登录光猫后台,在网页上配置DMZ/虚拟主机配置等防火墙规则也不会实际生效,实在离谱。
不可否认的是,桥接在绝大多数场景都是一步到位的便捷选择。但对于不方便进行桥接的笔者来说,iptables真香。
引用