From 6630d35eea6510834287a7004e55718f49a6232f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 13 Oct 2025 12:06:01 +0200 Subject: [PATCH 01/12] mod/notification-telegram: $FlushTelegramQueue: check for cert, again Chances are that messages have been queued before system was fully up or connected. Thus the certificate may be missing, and it should be checked again for on flush. --- mod/notification-telegram.rsc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc index 2eb90e12..ff9b4da2 100644 --- a/mod/notification-telegram.rsc +++ b/mod/notification-telegram.rsc @@ -21,6 +21,7 @@ :global TelegramQueue; :global TelegramMessageIDs; + :global CertificateAvailable; :global IsFullyConnected; :global LogPrint; @@ -29,6 +30,11 @@ :return false; } + :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :return false; + } + :local AllDone true; :local QueueLen [ :len $TelegramQueue ]; From 025b492783ad5a3dd084a6ecf4465878c970970c Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 10:27:27 +0200 Subject: [PATCH 02/12] global-functions: remove trailing space --- global-functions.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 98bc306c..55b52922 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -465,7 +465,7 @@ :local Error [ :tostr $3 ]; :global IfThenElse; - :global LogPrint; + :global LogPrint; :if ($ExitOK = "false") do={ $LogPrint error $Name ([ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \ From def540c965c40c28cce5ceef00e25132f5ab2d3f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 10:26:50 +0200 Subject: [PATCH 03/12] global-functions: introduce $NetMask4 --- global-functions.rsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 55b52922..5c98a206 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -61,6 +61,7 @@ :global MAX; :global MIN; :global MkDir; +:global NetMask4; :global NotificationFunctions; :global ParseDate; :global ParseKeyValueStore; @@ -990,6 +991,13 @@ :return true; } +# return an IPv4 netmask for CIDR +:set NetMask4 do={ + :local CIDR [ :tonum $1 ]; + + :return ((255.255.255.255 << (32 - $CIDR)) & 255.255.255.255); +} + # prepare NotificationFunctions array :if ([ :typeof $NotificationFunctions ] != "array") do={ :set NotificationFunctions ({}); From 9fa11cb79a2d0e23ff73b1317fdff123636fca10 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 10:42:23 +0200 Subject: [PATCH 04/12] mod/ipcalc: use $NetMask4 --- mod/ipcalc.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index eacff6d9..fecf6f26 100644 --- a/mod/ipcalc.rsc +++ b/mod/ipcalc.rsc @@ -34,9 +34,12 @@ # calculate and return netmask, network, min host, max host and broadcast :set IPCalcReturn do={ :local Input [ :tostr $1 ]; + + :global NetMask4; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + :local Mask [ $NetMask4 $Bits ]; :local Return { "address"=$Address; From 47309e5c03e32e05ed9435ed05f9549dfddd338f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 13:02:28 +0200 Subject: [PATCH 05/12] fw-addr-lists: normalize IPv4 addresses --- fw-addr-lists.rsc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index cd136f95..26e041aa 100644 --- a/fw-addr-lists.rsc +++ b/fw-addr-lists.rsc @@ -22,10 +22,12 @@ :global EitherOr; :global FetchHuge; :global HumanReadableNum; + :global IfThenElse; :global LogPrint; :global LogPrintOnce; :global LogPrintVerbose; :global MIN; + :global NetMask4; :global ScriptLock; :global WaitFullyConnected; @@ -114,8 +116,13 @@ :do { :local Branch; :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ - :if ($Address ~ "/32\$") do={ - :set Address [ :pick $Address 0 ([ :len $Address ] - 3) ]; + :local Net $Address; + :local CIDR 32; + :local Slash [ :find $Address "/" ]; + :if ([ :typeof $Slash ] = "num") do={ + :set Net [ :toip [ :pick $Address 0 $Slash ] ] + :set CIDR [ :pick $Address ($Slash + 1) [ :len $Address ] ]; + :set Address [ :tostr (([ :toip $Net ] & [ $NetMask4 $CIDR ]) . [ $IfThenElse ($CIDR < 32) ("/" . $CIDR) ]) ]; } :set Branch [ $GetBranch $Address ]; :set ($IPv4Addresses->$Branch->$Address) $TimeOut; From 6ad6f9aa08d558ff2e8ff3010fe5daec3c600c4a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 10:30:20 +0200 Subject: [PATCH 06/12] global-functions: introduce $NetMask6 RouterOS does not support bit shifting on IPv6 data types, so we have to split the problem: * each 16 bit block is calculated separately, as number * the complete netmask is assembled in a loop, as string * the final string is casted to correct data type --- global-functions.rsc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 5c98a206..ffa52776 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,24 @@ :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; + + :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) ":" ]); + } + :return [ :toip6 $Mask ]; +} + # prepare NotificationFunctions array :if ([ :typeof $NotificationFunctions ] != "array") do={ :set NotificationFunctions ({}); From d7a6eb1d0083c1d788e8febedaea67464361d271 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 15:13:14 +0200 Subject: [PATCH 07/12] global-functions: $NetMask6: implement simple caching The calculation is quite complex for something that needs to be done frequently, for example by `fw-addr-lists`. The number of possible netmasks is limited, so let's cache the results that were calculated already. --- global-functions.rsc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index ffa52776..5ede6546 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1008,13 +1008,25 @@ :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) ":" ]); } - :return [ :toip6 $Mask ]; + :set Mask [ :toip6 $Mask ]; + :set ($NetMask6Cache->$CIDR) $Mask; + :return $Mask; } # prepare NotificationFunctions array From ea05b69f7cfb1506e24117020a115af2d1b19c4a Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 13:02:14 +0200 Subject: [PATCH 08/12] fw-addr-lists: use $NetMask6 --- fw-addr-lists.rsc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc index 26e041aa..c85cc8bf 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; From b80b872e557e2513c7e9ee4c6f119e3ad56d4116 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 16 Oct 2025 17:31:15 +0200 Subject: [PATCH 09/12] mod/ipcalc: support IPv6 Well, some of these values do not make a lot of sense for IPv6... Something to be cleaned up later. --- mod/ipcalc.rsc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc index fecf6f26..d65d4724 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; } From 10b0ee7e8713e0ab4bf54b6f162647182a1e50c4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 7 Jun 2025 22:38:55 +0200 Subject: [PATCH 10/12] INITIAL-COMMANDS: drop the compatibility workaround... ... and make it depend in RouterOS 7.19 and its builtin certificates. --- INITIAL-COMMANDS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 40f609b9..2df29e0c 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -4,7 +4,7 @@ Initial commands [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.19-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) @@ -22,8 +22,8 @@ Run the complete base installation: :local CertFileName "ISRG-Root-X2.pem"; :local CertFingerprint "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; - :if (!(([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \ - [[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CertCommonName . "\" ] ]") ]] > 0)) do={ + :if (!([ /certificate/settings/get builtin-trust-anchors ] = "trusted" && \ + [ :len [ /certificate/builtin/find where common-name=$CertCommonName ] ] > 0)) do={ :put "Importing certificate..."; /tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value; :delay 1s; From beafaf4bf502ddac4eaafdad430853e07dca2934 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Sat, 7 Jun 2025 22:41:29 +0200 Subject: [PATCH 11/12] global-functions: $CertificateAvailable: drop the compatibility workaround... ... and make it depend in RouterOS 7.19 and its builtin certificates. --- README.md | 2 +- global-functions.rsc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 243e1fc5..50cc270c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RouterOS Scripts [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.19-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) diff --git a/global-functions.rsc b/global-functions.rsc index 5ede6546..349eac23 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.19 # requires device-mode, fetch, scheduler # # global functions @@ -123,8 +123,8 @@ :return false; } - :if (([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \ - [[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CommonName . "\" ] ]") ]] > 0) do={ + :if ([ /certificate/settings/get builtin-trust-anchors ] = "trusted" && \ + [ :len [ /certificate/builtin/find where common-name=$CommonName ] ] > 0) do={ :return true; } From 6041f5cb5cd01eac3ac06cb9d215054d3e6ae01e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 10 Oct 2025 09:11:27 +0200 Subject: [PATCH 12/12] doc/mod/ssh-keys-import: reverse old and new --- doc/mod/ssh-keys-import.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md index 49276d04..1273de81 100644 --- a/doc/mod/ssh-keys-import.md +++ b/doc/mod/ssh-keys-import.md @@ -38,7 +38,7 @@ import that key: $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; The third part of the key (`user` in this example) is inherited as -`key-owner` in RouterOS (or `info` starting with RouterOS 7.21beta2). Also +`info` in RouterOS (or `key-owner` with RouterOS 7.19.x and before). Also the `MD5` fingerprint is recorded, this helps to audit and verify the available keys.