mirror of
https://bitbucket.org/mangelo/snippets.git
synced 2024-11-23 11:21:00 +02:00
IPv6 Dynamic Prefix Delegation and firewall rules in Mikrotik.
This commit is contained in:
parent
3004d35320
commit
85f07cca35
@ -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.
|
Loading…
Reference in New Issue
Block a user