diff options
author | 2025-10-19 19:28:48 +0200 | |
---|---|---|
committer | 2025-10-22 19:05:38 +0200 | |
commit | ea4b5553c21bc99e8645133b6ac8fec90d53b190 (patch) | |
tree | 5e12b5b436e32c13154642bca2d509e71a8cd8b6 | |
parent | c62f2362517186f434570e2ed67c0d89844e1bdc (diff) | |
parent | b80b872e557e2513c7e9ee4c6f119e3ad56d4116 (diff) |
Merge branch 'netmask6' into nextHEADrouteros-7.21beta2-3nextmain
This branch is a follow-up on 9ceed0926a749c51ebc050d80cd33100ecdbcc5a
with clean solution. Read on for details...
The data type `ip6-prefix` used to hold what it was named for - an IPv6
prefix:
[user@mikrotik] > :put 2001:db8::dead:beef/32
2001:db8::/32
This changed with RouterOS 6.21beta2, which now allows that exact same
data type to hold something like "address with prefix length attached":
[user@mikrotik] > :put 2001:db8::dead:beef/32
2001:db8::dead:beef/32
My scripts (namely `fw-addr-lists`) relied on the old behaviour and broke.
The commit mentioned above was just a quick workaround, with rough edges,
and it could still fail.
Sadly RouterOS does not support bit shifting on IPv6 data types, so a
(completely) mathematical solution is out of scope.
This branch implements a new and better workaround, see the first commit
of branch (6ad6f9aa08d558ff2e8ff3010fe5daec3c600c4a) for details.
I opened a support ticket / feature request on this topic, let's see
what results it brings...
https://help.mikrotik.com/servicedesk/servicedesk/customer/portal/1/SUP-201881
-rw-r--r-- | fw-addr-lists.rsc | 8 | ||||
-rw-r--r-- | global-functions.rsc | 31 | ||||
-rw-r--r-- | mod/ipcalc.rsc | 23 |
3 files changed, 52 insertions, 10 deletions
diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 26e041a..c85cc8b 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -26,8 +26,8 @@ :global LogPrint; :global LogPrintOnce; :global LogPrintVerbose; - :global MIN; :global NetMask4; + :global NetMask6; :global ScriptLock; :global WaitFullyConnected; @@ -130,13 +130,13 @@ } :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={ :local Net $Address; - :local Cidr 64; + :local CIDR 128; :local Slash [ :find $Address "/" ]; :if ([ :typeof $Slash ] = "num") do={ :set Net [ :toip6 [ :pick $Address 0 $Slash ] ] - :set Cidr [ $MIN [ :pick $Address ($Slash + 1) [ :len $Address ] ] 64 ]; + :set CIDR [ :pick $Address ($Slash + 1) [ :len $Address ] ]; } - :set Address (([ :toip6 $Net ] & ffff:ffff:ffff:ffff::) . "/" . $Cidr); + :set Address (([ :toip6 $Net ] & [ $NetMask6 $CIDR ]) . "/" . $CIDR); :set Branch [ $GetBranch $Address ]; :set ($IPv6Addresses->$Branch->$Address) $TimeOut; :error true; diff --git a/global-functions.rsc b/global-functions.rsc index 5c98a20..5ede654 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -62,6 +62,7 @@ :global MIN; :global MkDir; :global NetMask4; +:global NetMask6; :global NotificationFunctions; :global ParseDate; :global ParseKeyValueStore; @@ -998,6 +999,36 @@ :return ((255.255.255.255 << (32 - $CIDR)) & 255.255.255.255); } +# return an IPv6 netmask for CIDR +:set NetMask6 do={ + :local FuncName $0; + :local CIDR [ :tostr $1 ]; + + :global IfThenElse; + :global MAX; + :global MIN; + + :global NetMask6Cache; + + :if ([ :typeof ($NetMask6Cache->$CIDR) ] = "ip6") do={ + :return ($NetMask6Cache->$CIDR); + } + + :if ([ :typeof $NetMask6Cache ] = "nothing") do={ + :set NetMask6Cache ({}); + } + + :local Mask ""; + :for I from=0 to=7 do={ + :set Mask ($Mask . \ + [ :convert from=num to=hex (0xffff - (0xffff >> [ :tonum [ $MIN [ $MAX ($CIDR - (16 * $I)) 0 ] 16 ] ])) ] . \ + [ $IfThenElse ($I < 7) ":" ]); + } + :set Mask [ :toip6 $Mask ]; + :set ($NetMask6Cache->$CIDR) $Mask; + :return $Mask; +} + # prepare NotificationFunctions array :if ([ :typeof $NotificationFunctions ] != "array") do={ :set NotificationFunctions ({}); diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index fecf6f2..d65d472 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -36,21 +36,32 @@ :local Input [ :tostr $1 ]; :global NetMask4; + :global NetMask6; - :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Address [ :pick $Input 0 [ :find $Input "/" ] ]; :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask [ $NetMask4 $Bits ]; + :local Mask; + :local One; + :if ([ :typeof [ :toip $Address ] ] = "ip") do={ + :set Address [ :toip $Address ]; + :set Mask [ $NetMask4 $Bits ]; + :set One 0.0.0.1; + } else={ + :set Address [ :toip6 $Address ]; + :set Mask [ $NetMask6 $Bits ]; + :set One ::1; + } - :local Return { + :local Return ({ "address"=$Address; "netmask"=$Mask; "networkaddress"=($Address & $Mask); "networkbits"=$Bits; "network"=(($Address & $Mask) . "/" . $Bits); - "hostmin"=(($Address & $Mask) | 0.0.0.1); - "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "hostmin"=(($Address & $Mask) | $One); + "hostmax"=(($Address | ~$Mask) ^ $One); "broadcast"=($Address | ~$Mask); - } + }); :return $Return; } |