运营商给家宽用户下发的IPv6前缀并不是一成不变的,在用户重新拨号或者一定时间后会发生改变.
对此RouterOS处理机制有些许问题,该脚本一定程度上修复了这些问题,可以进行借鉴以维持IPv6网络的安全性和可用性.
本文假设用户已经正常设置DHCP Client并通过SLAAC下发地址给局域网用户.
以下是我的防火墙配置,另外还设置了/ipv6/ND
中的MTU为PPPoE的MTU,其他配置比较简单(网上可找到)就不再重复了:
目前ROS存在的问题:
- 重新获取前缀后没有发送RA生命期为0的路由通告来弃用老的前缀.
- 防火墙不支持
/::ffff:ffff:ffff:ffff
形式的后缀匹配,使得防火墙规则编写困难.
解决方案:通过计划任务检测IPv6地址变化,设定特定服务器以外劫持所有DNS以便控制广告和科学上网,并在变化后发送路由通告和动态修改防火墙内容.
主要脚本(计划任务10s以上):
:global oldprefix
# Get current IPv6 prefix
:local v6prefix [/ipv6 dhcp-client get [/ipv6 dhcp-client find interface="pppoe-out1"] prefix]
:set v6prefix [:pick $v6prefix 0 [:find $v6prefix "/"]]
:set v6prefix [:pick $v6prefix 0 [:put ([:find $v6prefix "::"]+1)]]
:if ([:len $oldprefix]=0) do {
:set oldprefix $v6prefix
}
:if ($v6prefix!=$oldprefix) do {
:log info "ipv6 prefix has been changed to $v6prefix:/64"
# Update ip6tables firewall
:if ([:len $v6prefix]!=0) do {
:local v6addr
/ipv6 firewall address-list remove [/ipv6 firewall address-list find list="server"]
:set v6addr [:put ($v6prefix."后缀0")]
/ipv6 firewall address-list add list="server" address="$v6addr"
:set v6addr [:put ($v6prefix."后缀1")]
/ipv6 firewall filter set [/ipv6 firewall filter find comment="设备1"] dst-address="$v6addr"
/ipv6 firewall nat set [/ipv6 firewall nat find comment="DNS-Hijack-dst"] to-address="$v6addr"
/ipv6 firewall address-list add list="server" address="$v6addr"
:set v6addr [:put ($v6prefix."后缀2")]
/ipv6 firewall filter set [/ipv6 firewall filter find comment="设备2"] dst-address="$v6addr"
:set v6addr [:put ($v6prefix."后缀3")]
/ipv6 firewall filter set [/ipv6 firewall filter find comment="设备3"] dst-address="$v6addr"
:set v6addr [:put ($v6prefix.":1")] #本机
/ipv6 firewall nat set [/ipv6 firewall nat find comment="DNS-Hijack-src"] dst-address="$v6addr"
}
# Advertise old prefix as abandoned
:if ([:len $oldprefix]!=0) do {
:delay 3s
/ipv6 nd prefix add interface=bridge1 prefix="$oldprefix:/64" preferred-lifetime=0s valid-lifetime=0s
:delay 1s
/ipv6 nd prefix remove [/ipv6 nd prefix find prefix="$oldprefix:/64"]
}
:set oldprefix $v6prefix
}
使用该脚本后依然存在路由器重启后缀不能弃用,可以通过编写相应的重启和关机脚本解决,此处以重启为例:
# Advertise old prefix as abandoned
:global oldprefix
:if ([:len $oldprefix]!=0) do {
/ipv6 address set [/ipv6 address find interface=bridge1 address="$oldprefix:1/64"] disable=yes
:delay 1s
/ipv6 nd prefix add interface=bridge1 prefix="$oldprefix:/64" preferred-lifetime=0s valid-lifetime=0s
:delay 1s
/ipv6 nd prefix remove [/ipv6 nd prefix find interface=bridge1 prefix="$oldprefix:/64"]
:delay 1s
}
/system scheduler set [/system/scheduler find name="Update I
Pv6"] disabled=yes
:delay 1s
/system reboot;
以及在PPPoE连上和断开处(Profile里)添加脚本:
# On Up
delay 2s
:execute "dynamic_dnat"
delay 3s
# Link up IPv6
:if ([/ipv6 address get [/ipv6 address find interface=bridge1 from-pool=dhcpv6_pool0] disable]) do {
/ipv6 address set [/ipv6 address find interface=bridge1 from-pool=dhcpv6_pool0] disable=no
}
:delay 10s
/system scheduler set [/system/scheduler find name="Update I
Pv6"] disabled=no
# On Down
# Advertise old prefix as abandoned
:global oldprefix
:if ([:len $oldprefix]!=0) do {
/ipv6 address set [/ipv6 address find interface=bridge1 address="$oldprefix:1/64"] disable=yes
/ipv6 nd prefix add interface=bridge1 prefix="$oldprefix:/64" preferred-lifetime=0s valid-lifetime=0s
:delay 1s
/ipv6 nd prefix remove [/ipv6 nd prefix find interface=bridge1 prefix="$oldprefix:/64"]
}
/system scheduler set [/system/scheduler find name="Update I
Pv6"] disabled=yes