aboutsummaryrefslogtreecommitdiffstats
path: root/mod
diff options
context:
space:
mode:
Diffstat (limited to 'mod')
-rw-r--r--mod/bridge-port-to.rsc12
-rw-r--r--mod/bridge-port-vlan.rsc12
-rw-r--r--mod/inspectvar.rsc32
-rw-r--r--mod/ipcalc.rsc12
-rw-r--r--mod/notification-email.rsc93
-rw-r--r--mod/notification-gotify.rsc139
-rw-r--r--mod/notification-matrix.rsc61
-rw-r--r--mod/notification-ntfy.rsc32
-rw-r--r--mod/notification-telegram.rsc92
-rw-r--r--mod/scriptrunonce.rsc44
-rw-r--r--mod/ssh-keys-import.rsc35
11 files changed, 389 insertions, 175 deletions
diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc
index ec6f612..93eedce 100644
--- a/mod/bridge-port-to.rsc
+++ b/mod/bridge-port-to.rsc
@@ -1,16 +1,16 @@
#!rsc by RouterOS
# RouterOS script: mod/bridge-port-to
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
#
# reset bridge ports to default bridge
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md
+# https://rsc.eworm.de/doc/mod/bridge-port-to.md
:global BridgePortTo;
-:set BridgePortTo do={ :do {
+:set BridgePortTo do={ :onerror Err {
:local BridgePortTo [ :tostr $1 ];
:global IfThenElse;
@@ -65,6 +65,6 @@
$LogPrint info $0 ("Re-enabling interfaces...");
/interface/ethernet/enable $InterfaceReEnable;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc
index 6221646..6deee99 100644
--- a/mod/bridge-port-vlan.rsc
+++ b/mod/bridge-port-vlan.rsc
@@ -1,16 +1,16 @@
#!rsc by RouterOS
# RouterOS script: mod/bridge-port-vlan
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
#
# manage VLANs on bridge ports
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md
+# https://rsc.eworm.de/doc/mod/bridge-port-vlan.md
:global BridgePortVlan;
-:global BridgePortVlan do={ :do {
+:global BridgePortVlan do={ :onerror Err {
:local ConfigTo [ :tostr $1 ];
:global IfThenElse;
@@ -74,6 +74,6 @@
$LogPrint info $0 ("Re-enabling interfaces...");
/interface/ethernet/enable $InterfaceReEnable;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc
index 01724bb..fc1b366 100644
--- a/mod/inspectvar.rsc
+++ b/mod/inspectvar.rsc
@@ -1,23 +1,23 @@
#!rsc by RouterOS
# RouterOS script: mod/inspectvar
# Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
#
# inspect variables
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md
+# https://rsc.eworm.de/doc/mod/inspectvar.md
:global InspectVar;
:global InspectVarReturn;
# inspect variable and print on terminal
-:set InspectVar do={ :do {
+:set InspectVar do={ :onerror Err {
:global InspectVarReturn;
:put [ :tocrlf [ $InspectVarReturn $1 ] ];
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# inspect variable and return formatted string
@@ -25,6 +25,7 @@
:local Input $1;
:local Level (0 + [ :tonum $2 ]);
+ :global CharacterReplace;
:global IfThenElse;
:global InspectVarReturn;
@@ -33,14 +34,13 @@
:local Value [ :tostr $2 ];
:local Level [ :tonum $3 ];
- :local Indent "";
- :for I from=1 to=$Level step=1 do={
- :set Indent ($Indent . " ");
- }
- :return ($Indent . "-" . $Prefix . "-> " . $Value);
+ :global CharacterMultiply;
+
+ :return ([ $CharacterMultiply " " $Level ] . "-" . $Prefix . "-> " . $Value);
}
:local TypeOf [ :typeof $Input ];
+ :local Len [ :len $Input ];
:local Return [ $IndentReturn "type" $TypeOf $Level ];
:if ($TypeOf = "array") do={
@@ -50,6 +50,16 @@
[ $InspectVarReturn $Value ($Level + 2) ]);
}
} else={
+ :if ($TypeOf = "str") do={
+ :set $Return ($Return . "\n" . \
+ [ $IndentReturn "len" $Len $Level ]);
+ :if ([ :typeof [ :find $Input ("\r") ] ] = "num") do={
+ :set Input [ $CharacterReplace $Input ("\r") "" ];
+ }
+ :if ([ :typeof [ :find $Input ("\n") ] ] = "num") do={
+ :set Input [ $CharacterReplace $Input ("\n") " " ];
+ }
+ }
:if ($TypeOf != "nothing") do={
:set $Return ($Return . "\n" . \
[ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \
diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc
index 69dec8b..eacff6d 100644
--- a/mod/ipcalc.rsc
+++ b/mod/ipcalc.rsc
@@ -1,18 +1,18 @@
#!rsc by RouterOS
# RouterOS script: mod/ipcalc
# Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
#
# ip address calculation
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md
+# https://rsc.eworm.de/doc/mod/ipcalc.md
:global IPCalc;
:global IPCalcReturn;
# print netmask, network, min host, max host and broadcast
-:set IPCalc do={ :do {
+:set IPCalc do={ :onerror Err {
:local Input [ :tostr $1 ];
:global FormatLine;
@@ -27,8 +27,8 @@
[ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \
[ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \
[ $FormatLine "Broadcast" ($Values->"broadcast") ]) ];
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# calculate and return netmask, network, min host, max host and broadcast
diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc
index 6d700f5..ad9762a 100644
--- a/mod/notification-email.rsc
+++ b/mod/notification-email.rsc
@@ -1,12 +1,13 @@
#!rsc by RouterOS
# RouterOS script: mod/notification-email
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
+# requires device-mode, email, scheduler
#
# send notifications via e-mail
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-email.md
+# https://rsc.eworm.de/doc/mod/notification-email.md
:global EMailGenerateFrom;
:global FlushEmailQueue;
@@ -34,14 +35,16 @@
}
# flush e-mail queue
-:set FlushEmailQueue do={ :do {
+:set FlushEmailQueue do={ :onerror Err {
:global EmailQueue;
:global EitherOr;
:global EMailGenerateFrom;
+ :global FileExists;
:global IsDNSResolving;
:global IsTimeSync;
:global LogPrint;
+ :global RmFile;
:local AllDone true;
:local QueueLen [ :len $EmailQueue ];
@@ -88,35 +91,40 @@
:foreach Id,Message in=$EmailQueue do={
:if ([ :typeof $Message ] = "array" ) do={
- :local Attach ({});
:while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; }
- :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={
- :if ([ :len [ /file/find where name=$File ] ] = 1) do={
- :set Attach ($Attach, $File);
- } else={
- $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach.");
+ :onerror Err {
+ :local Attach ({});
+ :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={
+ :if ([ $FileExists $File ] = true) do={
+ :set Attach ($Attach, $File);
+ } else={
+ $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach.");
+ }
}
- }
- /tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \
- subject=($Message->"subject") body=($Message->"body") file=$Attach;
- :local Wait true;
- :do {
- :delay 1s;
- :local Status [ /tool/e-mail/get last-status ];
- :if ($Status = "succeeded") do={
- :set ($EmailQueue->$Id);
- :set Wait false;
- :if (($Message->"remove-attach") = true) do={
- :foreach File in=$Attach do={
- /file/remove $File;
+ /tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \
+ subject=($Message->"subject") body=($Message->"body") file=$Attach;
+ :local Wait true;
+ :do {
+ :delay 1s;
+ :local Status [ /tool/e-mail/get last-status ];
+ :if ($Status = "succeeded") do={
+ :set ($EmailQueue->$Id);
+ :set Wait false;
+ :if (($Message->"remove-attach") = true) do={
+ :foreach File in=$Attach do={
+ $RmFile $File;
+ }
}
}
- }
- :if ($Status = "failed") do={
- :set AllDone false;
- :set Wait false;
- }
- } while=($Wait = true);
+ :if ($Status = "failed") do={
+ :set AllDone false;
+ :set Wait false;
+ }
+ } while=($Wait = true);
+ } do={
+ $LogPrint warning $0 ("Sending queued mail failed: " . $Err);
+ :set AllDone false;
+ }
}
}
@@ -134,8 +142,8 @@
/system/scheduler/set interval=(($SchedVal->"run-count") . "m") \
comment="Waiting for retry..." $Scheduler;
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# generate filter for log-forward
@@ -175,6 +183,7 @@
:global IfThenElse;
:global NotificationEMailSignature;
:global NotificationEMailSubject;
+ :global SymbolForNotification;
:local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
:local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];
@@ -187,13 +196,23 @@
:if ([ :typeof $EmailQueue ] = "nothing") do={
:set EmailQueue ({});
}
+ :local Truncated false;
+ :local Body ($Notification->"message");
+ :if ([ :len $Body ] > 62000) do={
+ :set Body ([ :pick $Body 0 62000 ] . "...");
+ :set Truncated true;
+ }
:local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ];
+ :set Body ($Body . "\n" . \
+ [ $IfThenElse ([ :len ($Notification->"link") ] > 0) \
+ ("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ] . \
+ [ $IfThenElse ($Truncated = true) ("\n" . [ $SymbolForNotification "scissors" ] . \
+ "The message was too long and has been truncated!") ] . \
+ [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]);
:set ($EmailQueue->[ :len $EmailQueue ]) {
to=$To; cc=$Cc;
subject=[ $NotificationEMailSubject ($Notification->"subject") ];
- body=(($Notification->"message") . \
- [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \
- [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \
+ body=$Body; \
attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") };
:if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={
/system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \
@@ -247,12 +266,12 @@
}
# send notification via e-mail - expects at least two string arguments
-:set SendEMail do={ :do {
+:set SendEMail do={ :onerror Err {
:global SendEMail2;
$SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 });
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via e-mail - expects one array argument
diff --git a/mod/notification-gotify.rsc b/mod/notification-gotify.rsc
new file mode 100644
index 0000000..d8eafbe
--- /dev/null
+++ b/mod/notification-gotify.rsc
@@ -0,0 +1,139 @@
+#!rsc by RouterOS
+# RouterOS script: mod/notification-gotify
+# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
+# Leonardo David Monteiro <leo@cub3.xyz>
+# https://rsc.eworm.de/COPYING.md
+#
+# requires RouterOS, version=7.15
+# requires device-mode, fetch, scheduler
+#
+# send notifications via Gotify (gotify.net)
+# https://rsc.eworm.de/doc/mod/notification-gotify.md
+
+:global FlushGotifyQueue;
+:global NotificationFunctions;
+:global PurgeGotifyQueue;
+:global SendGotify;
+:global SendGotify2;
+
+# flush Gotify queue
+:set FlushGotifyQueue do={ :onerror Err {
+ :global GotifyQueue;
+
+ :global IsFullyConnected;
+ :global LogPrint;
+
+ :if ([ $IsFullyConnected ] = false) do={
+ $LogPrint debug $0 ("System is not fully connected, not flushing.");
+ :return false;
+ }
+
+ :local AllDone true;
+ :local QueueLen [ :len $GotifyQueue ];
+
+ :if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] > 0 && $QueueLen = 0) do={
+ $LogPrint warning $0 ("Flushing Gotify messages from scheduler, but queue is empty.");
+ }
+
+ :foreach Id,Message in=$GotifyQueue do={
+ :if ([ :typeof $Message ] = "array" ) do={
+ :onerror Err {
+ /tool/fetch check-certificate=yes-without-crl output=none http-method=post \
+ http-header-field=($Message->"headers") http-data=[ :serialize to=json ($Message->"message") ] \
+ ($Message->"url") as-value;
+ :set ($GotifyQueue->$Id);
+ } do={
+ $LogPrint debug $0 ("Sending queued Gotify message failed: " . $Err);
+ :set AllDone false;
+ }
+ }
+ }
+
+ :if ($AllDone = true && $QueueLen = [ :len $GotifyQueue ]) do={
+ /system/scheduler/remove [ find where name="_FlushGotifyQueue" ];
+ :set GotifyQueue;
+ }
+} do={
+ :global ExitError; $ExitError false $0 $Err;
+} }
+
+# send notification via Gotify - expects one array argument
+:set ($NotificationFunctions->"gotify") do={
+ :local Notification $1;
+
+ :global Identity;
+ :global IdentityExtra;
+ :global GotifyQueue;
+ :global GotifyServer;
+ :global GotifyServerOverride;
+ :global GotifyToken;
+ :global GotifyTokenOverride;
+
+ :global EitherOr;
+ :global FetchUserAgentStr;
+ :global IfThenElse;
+ :global LogPrint;
+ :global SymbolForNotification;
+
+ :local Server [ $EitherOr ($GotifyServerOverride->($Notification->"origin")) $GotifyServer ];
+ :local Token [ $EitherOr ($GotifyTokenOverride->($Notification->"origin")) $GotifyToken ];
+
+ :if ([ :len $Token ] = 0) do={
+ :return false;
+ }
+
+ :local Url ("https://" . $Server . "/message");
+ :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \
+ ("X-Gotify-Key: " . $Token); "Content-Type: application/json" });
+ :local Message ({
+ "title"=("[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")); \
+ "message"=(($Notification->"message") . "\n" . [ $IfThenElse ([ :len ($Notification->"link") ] > 0) \
+ ("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ]); \
+ "priority"=[ :tonum [ $IfThenElse ($Notification->"silent") 2 5 ] ] });
+
+ :onerror Err {
+ /tool/fetch check-certificate=yes-without-crl output=none http-method=post \
+ http-header-field=$Headers http-data=[ :serialize to=json $Message ] $Url as-value;
+ } do={
+ $LogPrint info $0 ("Failed sending Gotify notification: " . $Err . " - Queuing...");
+
+ :if ([ :typeof $GotifyQueue ] = "nothing") do={
+ :set GotifyQueue ({});
+ }
+ :set ($Message->"message") (($Notification->"message") . "\n" . \
+ [ $SymbolForNotification "alarm-clock" ] . "This message was queued since " . \
+ [ /system/clock/get date ] . " " . [ /system/clock/get time ] . " and may be obsolete.");
+ :set ($GotifyQueue->[ :len $GotifyQueue ]) \
+ { url=$Url; headers=$Headers; message=$Message };
+ :if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] = 0) do={
+ /system/scheduler/add name="_FlushGotifyQueue" interval=1m start-time=startup \
+ on-event=(":global FlushGotifyQueue; \$FlushGotifyQueue;");
+ }
+ }
+}
+
+# purge the Gotify queue
+:set PurgeGotifyQueue do={
+ :global GotifyQueue;
+
+ /system/scheduler/remove [ find where name="_FlushGotifyQueue" ];
+ :set GotifyQueue;
+}
+
+# send notification via Gotify - expects at least two string arguments
+:set SendGotify do={ :onerror Err {
+ :global SendGotify2;
+
+ $SendGotify2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
+} do={
+ :global ExitError; $ExitError false $0 $Err;
+} }
+
+# send notification via Gotify - expects one array argument
+:set SendGotify2 do={
+ :local Notification $1;
+
+ :global NotificationFunctions;
+
+ ($NotificationFunctions->"gotify") ("\$NotificationFunctions->\"gotify\"") $Notification;
+}
diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc
index aad8b42..e9b42a0 100644
--- a/mod/notification-matrix.rsc
+++ b/mod/notification-matrix.rsc
@@ -2,12 +2,13 @@
# RouterOS script: mod/notification-matrix
# Copyright (c) 2013-2025 Michael Gisbers <michael@gisbers.de>
# Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
+# requires device-mode, fetch, scheduler
#
# send notifications via Matrix
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-matrix.md
+# https://rsc.eworm.de/doc/mod/notification-matrix.md
:global FlushMatrixQueue;
:global NotificationFunctions;
@@ -18,7 +19,7 @@
:global SetupMatrixJoinRoom;
# flush Matrix queue
-:set FlushMatrixQueue do={ :do {
+:set FlushMatrixQueue do={ :onerror Err {
:global MatrixQueue;
:global IsFullyConnected;
@@ -38,7 +39,7 @@
:foreach Id,Message in=$MatrixQueue do={
:if ([ :typeof $Message ] = "array" ) do={
- :do {
+ :onerror Err {
/tool/fetch check-certificate=yes-without-crl output=none \
http-header-field=($Message->"headers") http-method=post \
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain");
@@ -46,8 +47,8 @@
("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \
"/send/m.room.message?access_token=" . $Message->"accesstoken") as-value;
:set ($MatrixQueue->$Id);
- } on-error={
- $LogPrint debug $0 ("Sending queued Matrix message failed.");
+ } do={
+ $LogPrint debug $0 ("Sending queued Matrix message failed: " . $Err);
:set AllDone false;
}
}
@@ -57,8 +58,8 @@
/system/scheduler/remove [ find where name="_FlushMatrixQueue" ];
:set MatrixQueue;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via Matrix - expects one array argument
@@ -128,15 +129,15 @@
[ $PrepareText $Label ] . "</a>");
}
- :do {
+ :onerror Err {
/tool/fetch check-certificate=yes-without-crl output=none \
http-header-field=$Headers http-method=post \
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain;
"format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \
("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \
"/send/m.room.message?access_token=" . $AccessToken) as-value;
- } on-error={
- $LogPrint info $0 ("Failed sending Matrix notification! Queuing...");
+ } do={
+ $LogPrint info $0 ("Failed sending Matrix notification: " . $Err . " - Queuing...");
:if ([ :typeof $MatrixQueue ] = "nothing") do={
:set MatrixQueue ({});
@@ -166,12 +167,12 @@
}
# send notification via Matrix - expects at least two string arguments
-:set SendMatrix do={ :do {
+:set SendMatrix do={ :onerror Err {
:global SendMatrix2;
$SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 });
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via Matrix - expects one array argument
@@ -195,14 +196,14 @@
:global MatrixHomeServer;
:local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ];
- :do {
+ :onerror Err {
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
http-header-field=({ [ $FetchUserAgentStr $0 ] }) \
("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data");
:set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url");
$LogPrint debug $0 ("Home server is: " . $MatrixHomeServer);
- } on-error={
- $LogPrint error $0 ("Failed getting home server!");
+ } do={
+ $LogPrint error $0 ("Failed getting home server: " . $Err);
:return false;
}
@@ -210,27 +211,27 @@
:set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ];
}
- :do {
+ :onerror Err {
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \
http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \
("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data");
:set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token");
$LogPrint debug $0 ("Access token is: " . $MatrixAccessToken);
- } on-error={
- $LogPrint error $0 ("Failed logging in (and getting access token)!");
+ } do={
+ $LogPrint error $0 ("Failed logging in (and getting access token): " . $Err);
:return false;
}
- :do {
+ :onerror Err {
/system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ];
/system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \
"# configuration snippet: mod/notification-matrix\n\n" . \
":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \
":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n");
$LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!");
- } on-error={
- $LogPrint error $0 ("Failed adding configuration snippet!");
+ } do={
+ $LogPrint error $0 ("Failed adding configuration snippet: " . $Err);
:return false;
}
}
@@ -247,24 +248,24 @@
:global MatrixHomeServer;
:global MatrixRoom;
- :do {
+ :onerror Err {
/tool/fetch check-certificate=yes-without-crl output=none \
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \
("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \
"/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value;
$LogPrint debug $0 ("Joined the room.");
- } on-error={
- $LogPrint error $0 ("Failed joining the room!");
+ } do={
+ $LogPrint error $0 ("Failed joining the room: " . $Err);
:return false;
}
- :do {
+ :onerror Err {
:local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ];
/system/script/set $Snippet source=([ get $Snippet source ] . \
":global MatrixRoom \"" . $MatrixRoom . "\";\n");
$LogPrint info $0 ("Appended configuration to configuration snippet. Please review!");
- } on-error={
- $LogPrint error $0 ("Failed appending configuration to snippet!");
+ } do={
+ $LogPrint error $0 ("Failed appending configuration to snippet: " . $Err);
:return false;
}
}
diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc
index 53ba9b4..7114020 100644
--- a/mod/notification-ntfy.rsc
+++ b/mod/notification-ntfy.rsc
@@ -1,12 +1,13 @@
#!rsc by RouterOS
# RouterOS script: mod/notification-ntfy
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
+# requires device-mode, fetch, scheduler
#
# send notifications via Ntfy (ntfy.sh)
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md
+# https://rsc.eworm.de/doc/mod/notification-ntfy.md
:global FlushNtfyQueue;
:global NotificationFunctions;
@@ -15,9 +16,8 @@
:global SendNtfy2;
# flush ntfy queue
-:set FlushNtfyQueue do={ :do {
+:set FlushNtfyQueue do={ :onerror Err {
:global NtfyQueue;
- :global NtfyMessageIDs;
:global IsFullyConnected;
:global LogPrint;
@@ -36,13 +36,13 @@
:foreach Id,Message in=$NtfyQueue do={
:if ([ :typeof $Message ] = "array" ) do={
- :do {
+ :onerror Err {
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
http-header-field=($Message->"headers") http-data=($Message->"text") \
($Message->"url") as-value;
:set ($NtfyQueue->$Id);
- } on-error={
- $LogPrint debug $0 ("Sending queued Ntfy message failed.");
+ } do={
+ $LogPrint debug $0 ("Sending queued Ntfy message failed: " . $Err);
:set AllDone false;
}
}
@@ -52,8 +52,8 @@
/system/scheduler/remove [ find where name="_FlushNtfyQueue" ];
:set NtfyQueue;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via ntfy - expects one array argument
@@ -107,7 +107,7 @@
:set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link"));
}
- :do {
+ :onerror Err {
:if ($Server = "ntfy.sh") do={
:if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={
$LogPrint warning $0 ("Downloading required certificate failed.");
@@ -116,8 +116,8 @@
}
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
http-header-field=$Headers http-data=$Text $Url as-value;
- } on-error={
- $LogPrint info $0 ("Failed sending ntfy notification! Queuing...");
+ } do={
+ $LogPrint info $0 ("Failed sending ntfy notification: " . $Err . " - Queuing...");
:if ([ :typeof $NtfyQueue ] = "nothing") do={
:set NtfyQueue ({});
@@ -143,12 +143,12 @@
}
# send notification via ntfy - expects at least two string arguments
-:set SendNtfy do={ :do {
+:set SendNtfy do={ :onerror Err {
:global SendNtfy2;
$SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via ntfy - expects one array argument
diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc
index f9700cf..2eb90e1 100644
--- a/mod/notification-telegram.rsc
+++ b/mod/notification-telegram.rsc
@@ -1,27 +1,28 @@
#!rsc by RouterOS
# RouterOS script: mod/notification-telegram
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
+# requires device-mode, fetch, scheduler
#
# send notifications via Telegram
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md
+# https://rsc.eworm.de/doc/mod/notification-telegram.md
:global FlushTelegramQueue;
+:global GetTelegramChatId;
:global NotificationFunctions;
:global PurgeTelegramQueue;
:global SendTelegram;
:global SendTelegram2;
# flush telegram queue
-:set FlushTelegramQueue do={ :do {
+:set FlushTelegramQueue do={ :onerror Err {
:global TelegramQueue;
:global TelegramMessageIDs;
:global IsFullyConnected;
:global LogPrint;
- :global UrlEncode;
:if ([ $IsFullyConnected ] = false) do={
$LogPrint debug $0 ("System is not fully connected, not flushing.");
@@ -37,16 +38,14 @@
:foreach Id,Message in=$TelegramQueue do={
:if ([ :typeof $Message ] = "array" ) do={
- :do {
+ :onerror Err {
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \
- http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \
- "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \
- "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data");
+ http-data=($Message->"http-data") as-value ]->"data");
:set ($TelegramQueue->$Id);
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
- } on-error={
- $LogPrint debug $0 ("Sending queued Telegram message failed.");
+ } do={
+ $LogPrint debug $0 ("Sending queued Telegram message failed: " . $Err);
:set AllDone false;
}
}
@@ -56,10 +55,49 @@
/system/scheduler/remove [ find where name="_FlushTelegramQueue" ];
:set TelegramQueue;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
+# get the chat id
+:set GetTelegramChatId do={ :onerror Err {
+ :global TelegramTokenId;
+
+ :global CertificateAvailable;
+ :global LogPrint;
+
+ :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
+ $LogPrint warning $0 ("Downloading required certificate failed.");
+ :return false;
+ }
+
+ :local Data;
+ :onerror Err {
+ :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
+ ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=0" . \
+ "&allowed_updates=%5B%22message%22%5D") as-value ]->"data");
+ } do={
+ $LogPrint warning $0 ("Fetching data failed: " . $Err);
+ :return false;
+ }
+
+ :local JSON [ :deserialize from=json value=$Data ];
+ :local Count [ :len ($JSON->"result") ];
+
+ :if ($Count = 0) do={
+ $LogPrint info $0 ("No message received.");
+ :return false;
+ }
+
+ :local Message ($JSON->"result"->($Count - 1)->"message");
+ $LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id"));
+ :if (($Message->"is_topic_message") = true) do={
+ $LogPrint info $0 ("The thread id is: " . ($Message->"message_thread_id"));
+ }
+} do={
+ :global ExitError; $ExitError false $0 $Err;
+} }
+
# send notification via telegram - expects one array argument
:set ($NotificationFunctions->"telegram") do={
:local Notification $1;
@@ -70,6 +108,8 @@
:global TelegramChatIdOverride;
:global TelegramMessageIDs;
:global TelegramQueue;
+ :global TelegramThreadId;
+ :global TelegramThreadIdOverride;
:global TelegramTokenId;
:global TelegramTokenIdOverride;
@@ -110,6 +150,9 @@
:local ChatId [ $EitherOr ($Notification->"chatid") \
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
+ :local ThreadId [ $EitherOr ($Notification->"threadid") \
+ [ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) \
+ [ $IfThenElse ([ :len ($TelegramChatIdOverride->($Notification->"origin")) ] = 0) $TelegramThreadId ] ] ];
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
@@ -144,19 +187,20 @@
(($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]);
}
- :do {
+ :local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
+ "&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \
+ "&disable_web_page_preview=true&parse_mode=MarkdownV2");
+ :onerror Err {
:if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
$LogPrint warning $0 ("Downloading required certificate failed.");
:error false;
}
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \
- http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
- "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \
- "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
+ http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
- } on-error={
- $LogPrint info $0 ("Failed sending Telegram notification! Queuing...");
+ } do={
+ $LogPrint info $0 ("Failed sending Telegram notification: " . $Err . " - Queuing...");
:if ([ :typeof $TelegramQueue ] = "nothing") do={
:set TelegramQueue ({});
@@ -164,8 +208,8 @@
:set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \
[ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \
" " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]);
- :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId;
- text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") };
+ :set ($TelegramQueue->[ :len $TelegramQueue ]) { tokenid=$TokenId;
+ http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) };
:if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={
/system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \
on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;");
@@ -182,12 +226,12 @@
}
# send notification via telegram - expects at least two string arguments
-:set SendTelegram do={ :do {
+:set SendTelegram do={ :onerror Err {
:global SendTelegram2;
$SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# send notification via telegram - expects one array argument
diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc
index 7e01e72..1d6aaf1 100644
--- a/mod/scriptrunonce.rsc
+++ b/mod/scriptrunonce.rsc
@@ -1,22 +1,23 @@
#!rsc by RouterOS
# RouterOS script: mod/scriptrunonece
# Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
-# requires RouterOS, version=7.14
+# requires RouterOS, version=7.15
#
# download script and run it once
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md
+# https://rsc.eworm.de/doc/mod/scriptrunonce.md
:global ScriptRunOnce;
# fetch and run script(s) once
-:set ScriptRunOnce do={ :do {
+:set ScriptRunOnce do={ :onerror Err {
:local Scripts [ :toarray $1 ];
:global ScriptRunOnceBaseUrl;
:global ScriptRunOnceUrlSuffix;
+ :global FetchHuge;
:global LogPrint;
:global ValidateSyntax;
@@ -29,26 +30,27 @@
:set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix);
}
- :local Source;
- :do {
- :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data");
- } on-error={
+ :local Source [ $FetchHuge $0 $Script true ];
+ :if ($Source = false) do={
$LogPrint warning $0 ("Failed fetching script '" . $Script . "'!");
+ :return false;
}
- :if ([ :len $Source ] > 0) do={
- :if ([ $ValidateSyntax $Source ] = true) do={
- :do {
- $LogPrint info $0 ("Running script '" . $Script . "' now.");
- [ :parse $Source ];
- } on-error={
- $LogPrint warning $0 ("The script '" . $Script . "' failed to run!");
- }
- } else={
- $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!");
- }
+ :if ([ $ValidateSyntax $Source ] = false) do={
+ $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!");
+ :return false;
+ }
+
+ :onerror Err {
+ $LogPrint info $0 ("Running script '" . $Script . "' now.");
+ [ :parse $Source ];
+ } do={
+ $LogPrint warning $0 ("The script '" . $Script . "' failed to run: " . $Err);
+ :return false;
}
+
+ :return true;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc
index ad3a81e..7bdc95d 100644
--- a/mod/ssh-keys-import.rsc
+++ b/mod/ssh-keys-import.rsc
@@ -1,24 +1,25 @@
#!rsc by RouterOS
# RouterOS script: mod/ssh-keys-import
# Copyright (c) 2020-2025 Christian Hesse <mail@eworm.de>
-# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
+# https://rsc.eworm.de/COPYING.md
#
# requires RouterOS, version=7.16
#
# import ssh keys for public key authentication
-# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md
+# https://rsc.eworm.de/doc/mod/ssh-keys-import.md
:global SSHKeysImport;
:global SSHKeysImportFile;
# import single key passed as string
-:set SSHKeysImport do={ :do {
+:set SSHKeysImport do={ :onerror Err {
:local Key [ :tostr $1 ];
:local User [ :tostr $2 ];
:global GetRandom20CharAlNum;
:global LogPrint;
:global MkDir;
+ :global RmDir;
:global WaitForFile;
:if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={
@@ -54,26 +55,27 @@
/file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5);
$WaitForFile $FileName;
- :do {
+ :onerror Err {
/user/ssh-keys/import public-key-file=$FileName user=$User;
$LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \
"MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'.");
- /file/remove "tmpfs/ssh-keys-import";
- } on-error={
- $LogPrint warning $0 ("Failed importing key.");
- /file/remove "tmpfs/ssh-keys-import";
+ $RmDir "tmpfs/ssh-keys-import";
+ } do={
+ $LogPrint warning $0 ("Failed importing key: " . $Err);
+ $RmDir "tmpfs/ssh-keys-import";
:return false;
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }
# import keys from a file
-:set SSHKeysImportFile do={ :do {
+:set SSHKeysImportFile do={ :onerror Err {
:local FileName [ :tostr $1 ];
:local User [ :tostr $2 ];
:global EitherOr;
+ :global FileExists;
:global LogPrint;
:global ParseKeyValueStore;
:global SSHKeysImport;
@@ -83,8 +85,7 @@
:return false;
}
- :local File [ /file/find where name=$FileName ];
- :if ([ :len $File ] = 0) do={
+ :if ([ $FileExists $FileName ] = true) do={
$LogPrint warning $0 ("File '" . $FileName . "' does not exist.");
:return false;
}
@@ -93,9 +94,7 @@
:foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={
:local Continue false;
:if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={
- :do {
- $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User;
- } on-error={
+ :if ([ $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User ] = false) do={
$LogPrint warning $0 ("Failed importing key for user '" . $User . "'.");
}
:set Continue true;
@@ -108,6 +107,6 @@
$LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.");
}
}
-} on-error={
- :global ExitError; $ExitError false $0;
+} do={
+ :global ExitError; $ExitError false $0 $Err;
} }