解决小米路由器ipv6端口精准放行问题

posts/%E8%A7%A3%E5%86%B3%E5%B0%8F%E7%B1%B3%E8%B7%AF%E7%94%B1%E5%99%A8ipv6%E7%AB%AF%E5%8F%A3%E7%B2%BE%E5%87%86%E6%94%BE%E8%A1%8C%E9%97%AE%E9%A2%98

背景

由于传统的 ipv4 公网联机方案带宽不够用(打游戏时游戏模组加太多而且人也多,所以打 BOSS 时容易出现卡死的情况)但又不想加钱,于是想利用 ipv6 联机。

由于我的小米路由器 R3G 打开 ipv6 后会对外部一切的流量进行拦截,导致 wifi 下的局域网设备即使有了公网 ipv6 也无法实现公网的功能,小米也没有提供关闭防火墙的功能(貌似其他型号的设备有)。

当然也可以使用有线中继模式,把设备交给光猫托管,但我的光猫会一刀切放行,等于所有设备全暴露在公网上,让人感到不安全,所以这个方案被放弃了。

所以要解决的主要就是 ipv6 端口放行问题,当然小米是一刀切拦截,但是我们不能这个放行也一刀切,所以就有了如下方案。

解决方案

更换开发版系统并开启 SSH

这个网上有很多教程了,这里不再多赘述。但由于开发版本太旧,没有开启 ipv6 功能需要我们手动开启。

开启 ipv6

ssh 连接到路由器后,使用vi编辑/etc/config/ipv6list if_off 'wan'修改为list if_on 'wan',修改后的文件如下:

config ipv6 'settings'
        list if_on 'wan'
        list if_on 'ipv6'
        option ipv6_show '1'
        option enabled '1'
        option mode 'native'

然后重启路由器后就启用 ipv6 了。

分析 ip6tables

执行ip6tables -L观察防火墙链规则,规则大致如下:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
delegate_input  all      anywhere             anywhere

Chain FORWARD (policy DROP)
target     prot opt source               destination
delegate_forward  all      anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
delegate_output  all      anywhere             anywhere

从规则可以看出,INPUTOUTPUT都为ACCEPT,仅有FORWARDDROP,这也解释了防火墙默认打开原因。

继续观察自定义链delegate_forward

target     prot opt source               destination
forwarding_rule  all      anywhere             anywhere             /* user chain for forwarding */
ACCEPT     all      anywhere             anywhere             ctstate RELATED,ESTABLISHED
DROP       all      anywhere             anywhere             ctstate INVALID
zone_lan_forward  all      anywhere             anywhere
zone_wan_forward  all      anywhere             anywhere
zone_ready_forward  all      anywhere             anywhere
reject     all      anywhere             anywhere

这更加表明几乎拦截了一切的外部 ip 访问,当然解决这个问题也非常的简单,在delegate_forward前附加一个ACCEPT规则就可以了。

在 delegate_forward 前附加额外放行规则

假如我要放行当前的局域网某台设备的 22 端口,只需要我的局域网设备的全局 ipv6 地址(而不是链路 ip 地址)和放行端口号 22 就可以了。

所以我们用[ipv6]代表可以从外部访问的全局 ipv6 地址(也就是你想从公网 ip 访问的地址),[port]代表可以通过外部访问的端口号。

以放行一个 TCP 连接为例,我们就有了如下命令:

ip6tables -I FORWARD -d [ipv6] -p tcp --dport [port] -j ACCEPT

设置成功后,我们可以在另一台公网上的 IP 通过命令nc -zv [ipv6] [port]方式来确定端口是否可达。

一些后续的安全考虑

通过ip a发现小米路由器开启 ipv6 后具有公网 ip,感觉到不安全又搓了几行规则,规则如下:

ip6tables -I INPUT -p tcp --dport 22 -j REJECT # 禁用SSH
ip6tables -I INPUT -p tcp --dport 53 -j REJECT # 禁用DNS
ip6tables -I INPUT -p udp --dport 53 -j REJECT # 禁用DNS
ip6tables -I INPUT -p icmpv6 --icmpv6-type echo-request -j DROP # 禁用PING6
ip6tables -I INPUT -p tcp --dport 53 -s fe80::/10 -j ACCEPT # 允许Link Local设备访问DNS
ip6tables -I INPUT -p udp --dport 53 -s fe80::/10 -j ACCEPT # 允许Link Local设备访问DNS

由于是插入规则,规则不能打乱然后把上述命令插入到/etc/rc.local中,开机自动会生效。

结论

这样就解决了小米路由器 ipv6 端口精确放行的问题,不过需要 ssh 登录,而且手敲 iptables,显得很硬核。不过放行 ipv6 端口也是一时只需,附加的 ip6tables 规则重启就失效了,但规则及其灵活。可以按照上文这一小结进行额外扩展,实现其他额外的放行需求。