ROS防火墙和RA通告随IPv6前缀自动更新脚本

ROS防火墙和RA通告随IPv6前缀自动更新脚本

运营商给家宽用户下发的IPv6前缀并不是一成不变的,在用户重新拨号或者一定时间后会发生改变.

对此RouterOS处理机制有些许问题,该脚本一定程度上修复了这些问题,可以进行借鉴以维持IPv6网络的安全性和可用性.

本文假设用户已经正常设置DHCP Client并通过SLAAC下发地址给局域网用户.

以下是我的防火墙配置,另外还设置了/ipv6/ND中的MTU为PPPoE的MTU,其他配置比较简单(网上可找到)就不再重复了:

Filter表

NAT表(DNS劫持)

Mangle表(MSS钳制)

RAW表(Ping大小限制)

目前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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注