IPv6 Dynamic Prefix Delegation and firewall rules in Mikrotik.

This commit is contained in:
Miguel Scapolla 2018-03-29 15:30:00 -03:00
parent 3004d35320
commit 85f07cca35
1 changed files with 688 additions and 0 deletions

View File

@ -0,0 +1,688 @@
Mikrotik - Dynamic IPv6 prefix delegation - Update firewall rules
------------------------------------------------------------------
### Introduction
-----------------
This text explains how to configure a Mikrotik router as IPv6 DHCP client in
the WAN interface to fetch a dynamic prefix via Prefix Delegation (PD), and
redistribute it on the LAN(s) interface(s) via Stateless Address
Autoconfiguration (SLAAC).
Because the IPv6 prefix received for the LAN network is dynamic and can change
in each refresh, there are a script that reconfigure the dst-address in the
IPv6 firewall filter rules every time the prefix changes. This firewall rules
permit (or block) specific traffic to the servers in the LAN network.
Also, the configuration includes the IPv4 section (DHCP client in the WAN,
and DHCP server in the LAN) for a dual stack network and miscellaneous
configuration.
This configuration is used typically in a home environment with a cablemodem
internet service provider wich support prefix delegation.
### Requirements
-----------------
* Every LAN network will have a prefix length of 64 (/64 netmask) automatically.
The script not work or have undesirable side effects with others prefix
lengths.
* Every LAN network must have a only one IPv6 address obtained from a
delegated prefix. You can set a one or more fixed secondary IPv6 address,
but no other obtained from a pool.
* Every IPv6 firewall filter rule must have the out-interface name configured.
The out-interface name is used to identify the rules to be changed and to
identify which new IPv6 prefix is used. If you need a fixed rule with no
dst-address change, leave the out-interface unconfigured.
* Tested and working in Mikrotik RouterOS 6.41.3.
### Configuration
------------------
#
# This configuration is an example. Feel free to make changes based on your
# needs. This example uses a one WAN interface to the cablemodem ISP and
# two LAN interfaces to the PCs and servers.
#
#
# Names of the interfaces.
#
/interface ethernet
set [ find default-name=ether1 ] name=LAN1
set [ find default-name=ether2 ] name=LAN2
set [ find default-name=ether3 ] name=WAN
#
# Pools for the IPv4 DHCP server.
#
# The IPv4 DHCP server leases the IP from this pools.
#
/ip pool
add name=POOL1 ranges=10.10.10.64/26
add name=POOL2 ranges=10.20.20.64/26
#
# IPv4 DHCP servers for LANs.
#
/ip dhcp-server
add address-pool=POOL1 disabled=no interface=LAN1 lease-time=2h name=DHCP1
add address-pool=POOL2 disabled=no interface=LAN2 lease-time=2h name=DHCP2
#
# Options for the IPv4 DHCP server.
#
/ip dhcp-server network
add address=10.10.10.0/24 dns-server=10.10.10.1 domain=DOMAIN1.MM gateway=10.10.10.1 netmask=24 ntp-server=10.10.10.1
add address=10.20.20.0/24 dns-server=10.20.20.1 domain=DOMAIN2.MM gateway=10.20.20.1 netmask=24 ntp-server=10.20.20.1
#
# Store leases for the IPv4 DHCP server.
#
/ip dhcp-server config
set store-leases-disk=never
#
# IPv4 address of the LAN interfaces.
#
/ip address
add address=10.10.10.1/24 interface=LAN1
add address=10.20.20.1/24 interface=LAN2
#
# IPv4 DHCP client in the WAN.
#
/ip dhcp-client
add dhcp-options=clientid,hostname disabled=no interface=WAN
#
# DNS relay.
#
/ip dns
set allow-remote-requests=yes cache-max-ttl=10m cache-size=4096KiB query-total-timeout=4s
#
# IPv4 bogon (martians) prefixes.
#
# The bogon or martians prefix are prefix no routeables
# or not used in internet.
#
/ip firewall address-list
add address=0.0.0.0/8 list=BOGONv4
add address=10.0.0.0/8 list=BOGONv4
add address=100.64.0.0/10 list=BOGONv4
add address=127.0.0.0/8 list=BOGONv4
add address=169.254.0.0/16 list=BOGONv4
add address=172.16.0.0/12 list=BOGONv4
add address=192.0.0.0/24 list=BOGONv4
add address=192.0.2.0/24 list=BOGONv4
add address=192.168.0.0/16 list=BOGONv4
add address=198.18.0.0/15 list=BOGONv4
add address=198.51.100.0/24 list=BOGONv4
add address=203.0.113.0/24 list=BOGONv4
add address=224.0.0.0/3 list=BOGONv4
#
# IPv4 firewall rules: input.
#
# Traffic destined to the router.
#
/ip firewall filter
add action=accept chain=input connection-state=established,related
add action=accept chain=input in-interface=LAN1
add action=accept chain=input in-interface=LAN2
add action=drop chain=input in-interface=WAN src-address-list=BOGONv4
add action=accept chain=input in-interface=WAN dst-port=<externalPort> protocol=tcp <...>
add action=accept chain=input in-interface=WAN dst-port=<externalPort> protocol=udp <...>
add <more accept rules here...>
add action=drop chain=input
#
# IPv4 firewall rules: forward.
#
# Traffic wich pass through the router.
#
/ip firewall filter
add action=accept chain=forward connection-state=established,related
add action=accept chain=forward in-interface=LAN1
add action=accept chain=forward in-interface=LAN2
add action=drop chain=forward in-interface=WAN src-address-list=BOGONv4
add action=accept chain=forward dst-address=<internalIP> dst-port=<internalPort> in-interface=WAN protocol=tcp <...>
add action=accept chain=forward dst-address=<internalIP> dst-port=<internalPort> in-interface=WAN protocol=udp <...>
add <more accept rules here...>
add action=drop chain=forward
#
# IPv4 port forward.
#
# Maps the external ports with the internal IPv4 address
# and ports.
#
/ip firewall nat
add action=dst-nat chain=dstnat dst-address-type=local dst-port=<externalPort> protocol=tcp to-addresses=<internalIP> to-ports=<internalPort>
add action=dst-nat chain=dstnat dst-address-type=local dst-port=<externalPort> protocol=udp to-addresses=<internalIP> to-ports=<internalPort>
add <more dst-nat rules here...>
#
# IPv4 dynamic source NAT.
#
/ip firewall nat
add action=masquerade chain=srcnat out-interface=WAN
#
# IPv6 address of the LAN interfaces.
#
# The network part of the IPv6 address (prefix) is taken from the pool
# (POOL6) obtained with prefix delegation. The host part of the IPv6
# address is configured manually.
#
# In this example, the host part of the IPv6 address of the interfaces
# is ::1. The netmask it will be /64 automatically from the pool.
#
/ipv6 address
add address=::1 from-pool=POOL6 interface=LAN1
add address=::1 from-pool=POOL6 interface=LAN2
#
# IPv6 DHCP client in the WAN interface.
#
# The DHCP client request an IPv6 address for the WAN interface and an IPv6
# prefix for the pool POOL6. The IPv6 default route is created in the routing
# table and the FW6RULES script is executed when the bind expires and the
# DHCP client obtains another IPv6 prefix for the pool. The FW6RULES script
# update the IPv6 firewall filter rules to the new dst-address.
#
/ipv6 dhcp-client
add add-default-route=yes interface=WAN pool-name=POOL6 request=address,prefix script=FW6RULES
#
# IPv6 bogon (martians) prefixes.
#
# The bogon or martians prefix are prefix no routeables
# or not used in internet. This list is a brief summary
# of the complete list: https://bit.ly/2uxN3G8 and
# https://bit.ly/2IZy2QN
#
/ipv6 firewall address-list
add address=::/3 list=BOGONv6
add address=4000::/2 list=BOGONv6
add address=8000::/2 list=BOGONv6
add address=c000::/3 list=BOGONv6
add address=e000::/4 list=BOGONv6
add address=f000::/5 list=BOGONv6
add address=f800::/6 list=BOGONv6
add address=fc00::/7 list=BOGONv6
add address=fe00::/9 list=BOGONv6
add address=fec0::/10 list=BOGONv6
add address=ff00::/8 list=BOGONv6
#
# IPv6 firewall rules: input.
#
# Traffic destined to the router.
#
# The ICMP and UDP traffic from and to fe80::/10 and ff02::/16 are used by
# the IPv6 DHCP client to obtain the address and prefix delegation.
#
/ipv6 firewall filter
add action=accept chain=input connection-state=established,related
add action=accept chain=input dst-address=fe80::/10 in-interface=WAN protocol=icmpv6 src-address=fe80::/10
add action=accept chain=input dst-address=ff02::/16 in-interface=WAN protocol=icmpv6 src-address=fe80::/10
add action=accept chain=input dst-address=fe80::/10 dst-port=546 in-interface=WAN protocol=udp src-address=fe80::/10
add action=accept chain=input in-interface=LAN1
add action=accept chain=input in-interface=LAN2
add action=drop chain=input in-interface=WAN src-address-list=BOGONv6
add <more accept rules here...>
add action=drop chain=input
#
# IPv6 firewall rules: forward.
#
# Traffic wich pass through the router.
#
# In the out-interface of every rule you must configure the correct LAN
# interface. This field is used by the script to identify the rule, the
# out interface, and the new IPv6 prefix of the interface when changes.
#
# The dst-address in the rule is the host part and mask of the IPv6 address
# of the internal servers. Initially you can set the full IPv6 address (actual
# prefix /64 + host part /64) and mask or only the host part (/64) and mask.
# Later, the FW6RULES script changes the dst-address of the rule to the right
# full IPv6 address.
#
# The host part of the IPv6 address in the server must be fixed to the same
# value configured in the firewall rule. This value must be the same across
# the server restarts. In the server, you must disable IPv6 privacy extension
# and it is convenient to configure the host part of the IPv6 address manually.
#
# In GNU/Linux you can disable the IPv6 privacy extension with this:
#
# echo "net.ipv6.conf.all.use_tempaddr=0" > /etc/sysctl.d/95-ipv6-privacy.conf
# echo "net.ipv6.conf.default.use_tempaddr=0" >> /etc/sysctl.d/95-ipv6-privacy.conf
#
# With this, the server set the same host part of the IPv6 address between
# reboots.
#
# Also, you can force the host part of the IPv6 address manually with the
# tokenized interface identifer support. In the /etc/network/interfaces:
#
# iface eth0 inet6 auto
# pre-up /sbin/ifconfig eth0 up
# pre-up /sbin/ip token set ::aaaa:bbbb:cccc:dddd dev eth0
#
# For example: if the IPv6 prefix obtained is 1111:2222:3333:4444::/64, the
# full IPv6 address of the server will be 1111:2222:3333:4444:aaaa:bbbb:cccc:dddd/64.
# The FW6RULES script detects this change and reconfigure the firewall rule.
# For more info, see here: https://bit.ly/2pQRZR3
#
# In summary:
# in dst-address: put the host part and mask of the server(s).
# in out-interface: put the name of the LAN interface.
# run the script manually only once: /system script run FW6RULES
#
/ipv6 firewall filter
add action=accept chain=forward connection-state=established,related
add action=accept chain=forward in-interface=LAN1
add action=accept chain=forward in-interface=LAN2
add action=drop chain=forward in-interface=WAN src-address-list=BOGONv6
add action=accept chain=forward dst-address=::aaaa:bbbb:cccc:dddd/128 dst-port=<Port> in-interface=WAN out-interface=LAN1 protocol=tcp <...>
add action=accept chain=forward dst-address=::aaaa:bbbb:cccc:dddd/128 dst-port=<Port> in-interface=WAN out-interface=LAN1 protocol=udp <...>
add action=accept chain=forward dst-address=::1111:2222:3333:4400/120 dst-port=<Port> in-interface=WAN out-interface=LAN2 protocol=tcp <...>
add action=accept chain=forward dst-address=::1111:2222:3333:4400/120 dst-port=<Port> in-interface=WAN out-interface=LAN2 protocol=udp <...>
add action=accept chain=forward dst-address=::8888:eeee:5555:0/112 dst-port=<Port> in-interface=LAN1 out-interface=LAN2 protocol=tcp <...>
add action=accept chain=forward dst-address=::8888:eeee:5555:0/112 dst-port=<Port> in-interface=LAN1 out-interface=LAN2 protocol=udp <...>
add <more accept rules here...>
add action=drop chain=forward
#
# IPv6 Neighbor Discovery.
#
# Set the interfaces in which the router advertisement is sent and
# the interval.
#
/ipv6 nd
set [ find default=yes ] disabled=yes
add interface=LAN1 mtu=1500 ra-interval=10s-30s
add interface=LAN2 mtu=1500 ra-interval=10s-30s
#
# IPv6 Neighbor Discovery.
#
# Set the preferred and valid lifetime of the prefixes advertised.
#
/ipv6 nd prefix default
set preferred-lifetime=2m valid-lifetime=2m30s
#
# Clock.
#
# Set the NTP client, server and the timezone.
#
/system ntp client
set enabled=yes primary-ntp=<IPv4Addr> secondary-ntp=<IPv4Addr>
/system ntp server
set enabled=yes
/system clock
set time-zone-autodetect=no time-zone-name=<TimeZone>
#
# Hostname of the router and no banner at login.
#
/system identity
set name=MIKROTIK
/system note
set show-at-login=no
#
# End of the configuration.
#
### Script
-----------
#
# Create the script with read and write permissions.
#
/system script
add name=FW6RULES policy=read,write
#
# Edit the source code of the script.
#
# Note: below is the script in raw mode wich you can copy and paste
# without the comments.
#
/system script
edit FW6RULES source
#
# Begin of the code.
#
#-- Wait for the DHCP completion.
:delay 5s;
#--
#-- Function: return the uncompressed value of an IPv6 address
#-- or a IPv6 address + mask.
#--
#-- Parameters:
#-- $1: IPv6 address to expand.
#--
#-- Examples:
#-- Param $1 Return
#-- ----------- ---------
#-- ::/128 0:0:0:0:0:0:0:0/128
#-- ::1/128 0:0:0:0:0:0:0:1/128
#-- 2002:3003::/112 2002:3003:0:0:0:0:0:0/112
#-- 2112:3113::4114:0/120 2112:3113:0:0:0:0:4114:0/120
#-- 2332:2:3:4:5:6:7:8/128 2332:2:3:4:5:6:7:8/128
#-- :: 0:0:0:0:0:0:0:0
#-- ::1 0:0:0:0:0:0:0:1
#-- 2002:3003:: 2002:3003:0:0:0:0:0:0
#-- 2112:3113::4114:0 2112:3113:0:0:0:0:4114:0
#-- 2332:2:3:4:5:6:7:8 2332:2:3:4:5:6:7:8
#--
:local EXPANDIP do={
#-- Original IPv6 address.
:local ORIGINAL "$1";
#-- Uncompressed IPv6 address.
:local EXPANDED "$ORIGINAL";
#-- Search for "::". If not found, then the IPv6 address
#-- is already uncompressed.
:local POSTWO [:find $ORIGINAL "::" -1];
:if ($POSTWO >= 0) do={
#-- Split the IPv6 address with the separator "::".
:local PREFIX [:pick $ORIGINAL 0 $POSTWO];
:local SUFFIX [:pick $ORIGINAL ($POSTWO + 2) 99];
#-- If any string is empty, set to "0". This happens when
#-- the IPv6 address starts and/or ends with "::".
:if ([:len $PREFIX] = 0) do={ :set PREFIX "0"; }
:if ([:len $SUFFIX] = 0) do={ :set SUFFIX "0"; }
#-- If the suffix starts with "/", insert a "0"
#-- before de mask. This happens when the IPv6
#-- address ends with "::/NN".
:if ($SUFFIX ~ "^/") do={ :set SUFFIX ("0" . $SUFFIX); }
#-- Count the ":" character of the IPv6 address.
:local CNTTWO 0;
:for NDX from=0 to=([:len $ORIGINAL] - 1) do={
:if ([:pick $ORIGINAL $NDX] = ":") do={
:set CNTTWO ($CNTTWO + 1);
}
}
#-- Calculate how much is needed to fill
#-- the IPv6 address with ":0:" in the middle
#-- to uncompress.
:set CNTTWO (8 - $CNTTWO);
#-- Calculate the mid string with ":0:" to
#-- fill the IPv6 address.
:local MEDFIX "";
:if ($CNTTWO > 0) do={
:for NDX from=1 to=$CNTTWO do={
:set MEDFIX ($MEDFIX . ":0");
}
}
:set MEDFIX ($MEDFIX . ":");
#-- Calculate the expanded IPv6 address.
:set EXPANDED ($PREFIX . $MEDFIX . $SUFFIX);
}
#-- Finish.
:return $EXPANDED;
}
#--
#-- Function: return the prefix or host part of an
#-- expanded IPv6 address.
#--
#-- The prefix and host boundary always is /64 regardless the
#-- mask of the IPv6 address.
#--
#-- Parameters:
#-- $1: expanded IPv6 address.
#-- $2: false: return the prefix part (first 64 bits).
#-- true: return the host part (last 64 bits) and mask.
#--
#-- Examples:
#-- $1 $2=false $2=true
#-- ------------------ ------------ ------------
#-- 1111:2222:3333:4444:aaaa:bbbb:cccc:dddd/128 1111:2222:3333:4444 aaaa:bbbb:cccc:dddd/128
#-- 1111:2222:3333:4444:aaaa:bbbb:cccc:dddd 1111:2222:3333:4444 aaaa:bbbb:cccc:dddd
#-- 0:1:2:3:4:5:6:7/120 0:1:2:3 4:5:6:7/120
#-- 0:1:2:3:4:5:6:7 0:1:2:3 4:5:6:7
#-- a:b:c:d:1:2:3:4/64 a:b:c:d 1:2:3:4/64
#--
:local GETNETHOST do={
#-- Parameters.
:local DIRIP "$1";
:local ISHOST "$2";
#-- Search for the fourth two points
#-- (the prefix / host boundary).
:local POSDT -2;
:for NUMDT from=1 to=4 do={
:set POSDT [:find $DIRIP ":" ($POSDT + 1)];
}
#-- String with the result.
:local RESULT "";
#-- Check for prefix / host part.
:if ($ISHOST = true) do={
#-- Calculate the host part.
:set RESULT [:pick $DIRIP ($POSDT + 1) 99];
} else={
#-- Calculate the prefix part.
:set RESULT [:pick $DIRIP 0 $POSDT];
}
#-- Finish.
:return $RESULT;
}
#--
#-- Get the IPv6 prefix of every LAN interface.
#--
#-- Fill the NETLIST array with the name and the expanded
#- IPv6 prefix:
#--
#-- NETLIST = { "NAME1" -> "PREFIX1";
#-- "NAME2" -> "PREFIX2";
#-- .... -> .... }
#--
#-- Considers only interfaces with an IPv6 pool associated.
#-- If a interface have more than one IPv6 address from a pool,
#-- the algorithm takes into account only the last IPv6 address
#-- obtained for that interface and change the firewall rule
#-- with that prefix.
#--
#-- Example:
#-- NETLIST = { "LAN1" -> "2002:3440:3efa:3299";
#-- "LAN2" -> "2003:0:0:0"; }
#--
:local NETLIST ({});
#-- Loop through all interfaces with global IPv6 address.
:foreach INTNDX in=[/ipv6 address find global] do={
#-- Get the name of the pool of the interface.
:local POOLNAM [/ipv6 address get number=$INTNDX from-pool];
#-- Check if is a valid pool name.
#-- If the DHCP proccess fails or the interface not obtain the
#-- IPv6 address from a pool, the pool name is invalid.
:if ([:len $POOLNAM] > 0) do={
#-- Get the index of the pool.
:local POOLNDX [/ipv6 pool find name=$POOLNAM];
#-- Check if is a valid index.
:if ([:len $POOLNDX] > 0) do={
#--- Check if is a valid IPv6 prefix.
#--- If the DHCP proccess fails, the pool not have a valid prefix.
:if ([:len [/ipv6 pool get number=$POOLNDX prefix]] > 0) do={
#-- The pool is valid, then the IPv6 address of the interface
#-- is valid. Get the IPv6 address of the interface.
:local INTNETW [/ipv6 address get number=$INTNDX address];
#-- Check if the netmask is /64.
:if ($INTNETW ~ "/64\$") do={
#-- Get the name of the interface.
:local INTNAME [/ipv6 address get number=$INTNDX interface];
#-- Fill the array. Expand the IPv6 address and get the prefix part.
:set ($NETLIST->$INTNAME) [$GETNETHOST [$EXPANDIP $INTNETW] false];
}
}
}
}
}
#--
#-- Check every IPv6 firewall filter rule. Change the dst-address of the
#-- rules when is necessary.
#--
#-- The rules must be configured with the out-interface to match the NETLIST
#-- array.
#--
#-- Get every firewall filter rule (only forward chain).
:foreach RULENDX in=[/ipv6 firewall filter find chain="forward"] do={
#-- Get the out-interface of the rule.
:local RULELAN [/ipv6 firewall filter get number=$RULENDX out-interface];
#-- Get the new IPv6 prefix of the out-interface of the rule.
:local NEWPRFX ($NETLIST->$RULELAN);
#-- Check if the out-interface have a valid IPv6 prefix.
:if ([:len $NEWPRFX] > 0) do={
#-- Get the destination address of the rule.
:local RULEDST [$EXPANDIP [/ipv6 firewall filter get number=$RULENDX dst-address]];
#-- Calculate the new IPv6 address of the rule
#-- with the new IPv6 prefix.
:local NEWADDR ($NEWPRFX . ":" . [$GETNETHOST $RULEDST true]);
#-- Check if the dst address of the rule is different
#-- of the new calculated address.
:if ($RULEDST != $NEWADDR) do={
#-- Change the dst-address of the rule.
:local RET [/ipv6 firewall filter set numbers=$RULENDX dst-address=$NEWADDR];
#-- Log the change.
:log info ("fw6rules: ipv6 fw rule " . $RULENDX . " changed, " . $RULELAN . " new dstaddr " . $NEWADDR);
}
}
}
#-- Finish.
:log info ("fw6rules: executed");
### Raw script
---------------
/system script
add name=FW6RULES policy=read,write source="\
\n:delay 5s;\
\n\
\n:local EXPANDIP do={\
\n :local ORIGINAL \"\$1\";\
\n :local EXPANDED \"\$ORIGINAL\";\
\n :local POSTWO [:find \$ORIGINAL \"::\" -1];\
\n :if (\$POSTWO >= 0) do={\
\n :local PREFIX [:pick \$ORIGINAL 0 \$POSTWO];\
\n :local SUFFIX [:pick \$ORIGINAL (\$POSTWO + 2) 99];\
\n :if ([:len \$PREFIX] = 0) do={ :set PREFIX \"0\"; }\
\n :if ([:len \$SUFFIX] = 0) do={ :set SUFFIX \"0\"; }\
\n :if (\$SUFFIX ~ \"^/\") do={ :set SUFFIX (\"0\" . \$SUFFIX); }\
\n\
\n :local CNTTWO 0;\
\n :for NDX from=0 to=([:len \$ORIGINAL] - 1) do={\
\n :if ([:pick \$ORIGINAL \$NDX] = \":\") do={\
\n :set CNTTWO (\$CNTTWO + 1);\
\n }\
\n }\
\n :set CNTTWO (8 - \$CNTTWO);\
\n\
\n :local MEDFIX \"\";\
\n :if (\$CNTTWO > 0) do={\
\n :for NDX from=1 to=\$CNTTWO do={\
\n :set MEDFIX (\$MEDFIX . \":0\");\
\n }\
\n }\
\n :set MEDFIX (\$MEDFIX . \":\");\
\n :set EXPANDED (\$PREFIX . \$MEDFIX . \$SUFFIX);\
\n }\
\n :return \$EXPANDED;\
\n }\
\n\
\n:local GETNETHOST do={\
\n :local DIRIP \"\$1\";\
\n :local ISHOST \"\$2\";\
\n :local POSDT -2;\
\n :for NUMDT from=1 to=4 do={\
\n :set POSDT [:find \$DIRIP \":\" (\$POSDT + 1)];\
\n }\
\n :local RESULT \"\";\
\n :if (\$ISHOST = true) do={\
\n :set RESULT [:pick \$DIRIP (\$POSDT + 1) 99];\
\n } else={\
\n :set RESULT [:pick \$DIRIP 0 \$POSDT];\
\n }\
\n :return \$RESULT;\
\n }\
\n\
\n:local NETLIST ({});\
\n:foreach INTNDX in=[/ipv6 address find global] do={\
\n :local POOLNAM [/ipv6 address get number=\$INTNDX from-pool];\
\n :if ([:len \$POOLNAM] > 0) do={\
\n :local POOLNDX [/ipv6 pool find name=\$POOLNAM];\
\n :if ([:len \$POOLNDX] > 0) do={\
\n :if ([:len [/ipv6 pool get number=\$POOLNDX prefix]] > 0) do={\
\n :local INTNETW [/ipv6 address get number=\$INTNDX address];\
\n :if (\$INTNETW ~ \"/64\\\$\") do={\
\n :local INTNAME [/ipv6 address get number=\$INTNDX interface];\
\n :set (\$NETLIST->\$INTNAME) [\$GETNETHOST [\$EXPANDIP \$INTNETW] false];\
\n }\
\n }\
\n }\
\n }\
\n }\
\n\
\n:foreach RULENDX in=[/ipv6 firewall filter find chain=\"forward\"] do={\
\n :local RULELAN [/ipv6 firewall filter get number=\$RULENDX out-interface];\
\n :local NEWPRFX (\$NETLIST->\$RULELAN);\
\n :if ([:len \$NEWPRFX] > 0) do={\
\n :local RULEDST [\$EXPANDIP [/ipv6 firewall filter get number=\$RULENDX dst-address]];\
\n :local NEWADDR (\$NEWPRFX . \":\" . [\$GETNETHOST \$RULEDST true]);\
\n :if (\$RULEDST != \$NEWADDR) do={\
\n :local RET [/ipv6 firewall filter set numbers=\$RULENDX dst-address=\$NEWADDR];\
\n :log info (\"fw6rules: ipv6 fw rule \" . \$RULENDX . \" changed, \" . \$RULELAN . \" new dstaddr \" . \$NEWADDR);\
\n }\
\n }\
\n }\
\n\
\n:log info (\"fw6rules: executed\");\
\n"
### End
--------
If you wants a new feature or found a bug, please open an issue in BitBucket:
https://bitbucket.org/mangelo/snippets/src
Thanks.