aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTIONS.md1
-rw-r--r--INITIAL-COMMANDS.md1
-rw-r--r--README.md4
-rw-r--r--check-certificates3
-rw-r--r--global-config8
-rw-r--r--global-config-overlay5
-rw-r--r--global-config.changes2
-rw-r--r--global-functions198
-rw-r--r--log-forward28
9 files changed, 170 insertions, 80 deletions
diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md
index a78b0df..92cf2e7 100644
--- a/CONTRIBUTIONS.md
+++ b/CONTRIBUTIONS.md
@@ -21,6 +21,7 @@ Add yourself to the list,
* Christoph Boss (@Kampfwurst)
* Klaus Michael Rübsam
* Linux-Schmie.de Michael Gisbers
+* Manuel Kuhn
* Marek Čábák
* Reiner Vehrenkamp
diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md
index 9a5d6c8..fa32654 100644
--- a/INITIAL-COMMANDS.md
+++ b/INITIAL-COMMANDS.md
@@ -17,7 +17,6 @@ procedure please follow [the long way in detail](README.md#the-long-way-in-detai
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={
/ system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data");
}
- / system script set comment="ignore" global-config-overlay;
/ system script { run global-config; run global-config-overlay; run global-functions; }
/ system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }";
:global CertificateNameByCN;
diff --git a/README.md b/README.md
index 14b32db..090aab9 100644
--- a/README.md
+++ b/README.md
@@ -92,10 +92,6 @@ Now let's download the main scripts and add them in configuration on the fly.
[admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }
-Mark `global-config-overlay` not to be overwritten by future updates.
-
- [admin@MikroTik] > / system script set comment="ignore" global-config-overlay
-
The configuration needs to be tweaked for your needs. Edit
`global-config-overlay`, copy configuration from
[`global-config`](global-config) (the one without `-overlay`).
diff --git a/check-certificates b/check-certificates
index 68be7ee..f99b20a 100644
--- a/check-certificates
+++ b/check-certificates
@@ -40,6 +40,7 @@ $WaitFullyConnected;
:if ([ :len $CertRenewUrl ] = 0) do={
$LogPrintExit2 info $0 ("No CertRenewUrl given.") true;
}
+ $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false;
:foreach Type in={ ".pem"; ".p12" } do={
:local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type);
@@ -48,7 +49,7 @@ $WaitFullyConnected;
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
$WaitForFile $CertFileName;
:foreach PassPhrase in=$CertRenewPass do={
- / certificate import file-name=$CertFileName passphrase=$PassPhrase;
+ / certificate import file-name=$CertFileName passphrase=$PassPhrase as-value;
}
/ file remove [ find where name=$CertFileName ];
diff --git a/global-config b/global-config
index 9c8dbea..107ef19 100644
--- a/global-config
+++ b/global-config
@@ -55,9 +55,11 @@
# This defines a filter on log topics not to be forwarded.
:global LogForwardFilter "(debug|info)";
-# ... and the same for log message text.
-:global LogForwardFilterMessage "(^\$|^Error sending e-mail <.* Log Forwarding>:)";
-#:global LogForwardFilterMessage "(^\$|message text|...)";
+# ... and the same for log message text. Regular expressions are supported.
+# Do *NOT* set an empty string - that will filter everything!
+:global LogForwardFilterMessage [];
+#:global LogForwardFilterMessage "message text";
+#:global LogForwardFilterMessage "(message text|another text|...)";
# Specify an address to enable auto update to version assumed safe.
# The configured channel (bugfix, current, release-candidate) is appended.
diff --git a/global-config-overlay b/global-config-overlay
index 10376c7..850e6d8 100644
--- a/global-config-overlay
+++ b/global-config-overlay
@@ -1,5 +1,4 @@
-#!rsc by RouterOS
-# RouterOS script: global-config-overlay
+# Overlay for global configuration by RouterOS Scripts
# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
#
@@ -8,7 +7,7 @@
# Make sure all configuration properties are up to date and this
# value is in sync with value in script 'global-functions'!
-# Comment or remove to disable change notifications.
+# Comment or remove to disable news and change notifications.
:global GlobalConfigVersion 47;
# Copy configuration from global-config here and modify it.
diff --git a/global-config.changes b/global-config.changes
index 2bc18c0..2dc68f7 100644
--- a/global-config.changes
+++ b/global-config.changes
@@ -1,4 +1,4 @@
-# RouterOS global-config changes
+# News, changes and migration by RouterOS Scripts
# Copyright (c) 2019-2021 Christian Hesse <mail@eworm.de>
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
diff --git a/global-functions b/global-functions
index 7de3d72..387e4c0 100644
--- a/global-functions
+++ b/global-functions
@@ -24,6 +24,7 @@
:global DeviceInfo;
:global DNSIsResolving;
:global DownloadPackage;
+:global EscapeForRegEx;
:global FlushEmailQueue;
:global FlushTelegramQueue;
:global GetMacVendor;
@@ -35,6 +36,7 @@
:global LogPrintExit2;
:global MkDir;
:global ParseKeyValueStore;
+:global QuotedPrintable;
:global RandomDelay;
:global RequiredRouterOS;
:global ScriptFromTerminal;
@@ -83,7 +85,7 @@
}
:local CertVal [ / certificate get [ find where common-name=$CommonName ] ];
- :do {
+ :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={
:if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={
$LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \
"\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false;
@@ -92,7 +94,7 @@
}
}
:set CertVal [ / certificate get [ find where skid=($CertVal->"akid") ] ];
- } while=(($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid"));
+ }
:return true;
}
@@ -118,7 +120,7 @@
$UrlFileName . $ScriptUpdatesUrlSuffix) \
dst-path=$LocalFileName as-value;
$WaitForFile $LocalFileName;
- / certificate import file-name=$LocalFileName passphrase="";
+ / certificate import file-name=$LocalFileName passphrase="" as-value;
/ file remove $LocalFileName;
:foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={
@@ -229,10 +231,10 @@
:do {
:resolve "low-ttl.eworm.de";
- :return true;
} on-error={
:return false;
}
+ :return true;
}
# download package from upgrade server
@@ -288,6 +290,28 @@
:return false;
}
+# escape for regular expression
+:set EscapeForRegEx do={
+ :local Input [ :tostr $1 ];
+
+ :if ([ :len $Input ] = 0) do={
+ :return "";
+ }
+
+ :local Return "";
+ :local Chars "^.[]\$()|*+\?{}\\";
+
+ :for I from=0 to=([ :len $Input ] - 1) do={
+ :local Char [ :pick $Input $I ];
+ :if ([ :find $Chars $Char ]) do={
+ :set Char ("\\" . $Char);
+ }
+ :set Return ($Return . $Char);
+ }
+
+ :return $Return;
+}
+
# flush e-mail queue
:set FlushEmailQueue do={
:global EmailQueue;
@@ -550,6 +574,42 @@
:return $Result;
}
+# convert string to quoted-printable
+:global QuotedPrintable do={
+ :local Input [ :tostr $1 ];
+
+ :if ([ :len $Input ] = 0) do={
+ :return $Input;
+ }
+
+ :local Return "";
+ :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \
+ "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \
+ "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \
+ "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \
+ "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF");
+ :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" };
+
+ :for I from=0 to=([ :len $Input ] - 1) do={
+ :local Char [ :pick $Input $I ];
+ :local Replace [ :find $Chars $Char ];
+
+ :if ($Char = "=") do={
+ :set Char "=3D";
+ }
+ :if ([ :typeof $Replace ] = "num") do={
+ :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16)));
+ }
+ :set Return ($Return . $Char);
+ }
+
+ :if ($Input = $Return) do={
+ :return $Input;
+ }
+
+ :return ("=\?utf-8\?Q\?" . $Return . "\?=");
+}
+
# delay a random amount of seconds
:set RandomDelay do={
:global GetRandomNumber;
@@ -629,6 +689,7 @@
}
}
+ :local ExpectedConfigVersionBefore $ExpectedConfigVersion;
:local ScriptInstallUpdateBefore [ :tostr $ScriptInstallUpdate ];
:foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={
@@ -711,18 +772,12 @@
}
}
- :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \
- $GlobalConfigVersion < $ExpectedConfigVersion) do={
+ :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={
:global GlobalConfigChanges;
:global GlobalConfigMigration;
:local ChangeLogCode;
- :local NotificationMessage ("Current configuration on " . $Identity . \
- " is out of date. Please update global-config-overlay, then increase " . \
- "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \
- ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay.");
- $LogPrintExit2 info $0 ($NotificationMessage) false;
- $LogPrintExit2 debug $0 ("Fetching changelog.") false;
+ $LogPrintExit2 debug $0 ("Fetching news, changes and migration.") false;
:do {
:local Result [ / tool fetch check-certificate=yes-without-crl \
($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \
@@ -731,52 +786,68 @@
:set ChangeLogCode ($Result->"data");
}
} on-error={
- $LogPrintExit2 warning $0 ("Failed fetching changes!") false;
- :set NotificationMessage ($NotificationMessage . \
- "\n\nChanges are not available.");
+ $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false;
}
:if ([ :len $ChangeLogCode ] > 0) do={
:if ([ $ValidateSyntax $ChangeLogCode ] = true) do={
- :set NotificationMessage ($NotificationMessage . "\n\nChanges:");
[ :parse $ChangeLogCode ];
- :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={
- :local Migration ($GlobalConfigMigration->[ :tostr $I ]);
- :if ([ :typeof $Migration ] = "str") do={
- :if ([ $ValidateSyntax $Migration ] = true) do={
- $LogPrintExit2 info $0 ("Applying migration: " . $Migration) false;
- [ :parse $Migration ];
- } else={
- $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false;
- }
+ } else={
+ $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false;
+ }
+ }
+
+ :if ([ :len $GlobalConfigMigration ] > 0) do={
+ :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={
+ :local Migration ($GlobalConfigMigration->[ :tostr $I ]);
+ :if ([ :typeof $Migration ] = "str") do={
+ :if ([ $ValidateSyntax $Migration ] = true) do={
+ $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false;
+ [ :parse $Migration ];
+ } else={
+ $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false;
}
- :set NotificationMessage ($NotificationMessage . \
- "\n " . [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . \
- $GlobalConfigChanges->[ :tostr $I ]);
- $LogPrintExit2 info $0 ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false;
}
- :set GlobalConfigChanges;
- :set GlobalConfigMigration;
+ }
+ }
+
+ :if ($SentConfigChangesNotification != $ExpectedConfigVersion && \
+ $GlobalConfigVersion < $ExpectedConfigVersion) do={
+ :local NotificationMessage ("Current configuration on " . $Identity . \
+ " is out of date. Please update global-config-overlay, then increase " . \
+ "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \
+ ") to " . $ExpectedConfigVersion . " and re-run global-config-overlay.");
+ $LogPrintExit2 info $0 ($NotificationMessage) false;
+
+ :if ([ :len $GlobalConfigChanges ] > 0) do={
+ :set NotificationMessage ($NotificationMessage . "\n\nChanges:");
+ :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={
+ :local Change ($GlobalConfigChanges->[ :tostr $I ]);
+ :set NotificationMessage ($NotificationMessage . "\n " . \
+ [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change);
+ $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false;
+ }
} else={
- $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false;
+ :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available.");
+ }
+
+ :local Link;
+ :if ($IDonate != true) do={
:set NotificationMessage ($NotificationMessage . \
- "\n\nChanges are not available.");
+ "\n\n==== donation hint ====\n" . \
+ "This project is developed in private spare time and usage is " . \
+ "free of charge for you. If you like the scripts and think this is " . \
+ "of value for you or your business please consider a donation.");
+ :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate";
}
- }
- :local Link;
- :if ($IDonate != true) do={
- :set NotificationMessage ($NotificationMessage . \
- "\n\n==== donation hint ====\n" . \
- "This project is developed in private spare time and usage is " . \
- "free of charge for you. If you like the scripts and think this is " . \
- "of value for you or your business please consider a donation.");
- :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate";
+ $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \
+ $NotificationMessage $Link;
+ :set SentConfigChangesNotification $ExpectedConfigVersion;
}
- $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \
- $NotificationMessage $Link;
- :set SentConfigChangesNotification $ExpectedConfigVersion;
+ :set GlobalConfigChanges;
+ :set GlobalConfigMigration;
}
:if ($ScriptInstallUpdateBefore != [ :tostr $ScriptInstallUpdate ]) do={
@@ -806,8 +877,9 @@
:global EmailGeneralCc;
:global EmailQueue;
- :global LogPrintExit2;
:global IfThenElse;
+ :global LogPrintExit2;
+ :global QuotedPrintable;
:if ([ :len $EmailGeneralTo ] = 0) do={
:return false;
@@ -818,7 +890,8 @@
}
:local Signature [ / system note get note ];
:set ($EmailQueue->[ :len $EmailQueue ]) {
- to=$EmailGeneralTo; cc=$EmailGeneralCc; subject=("[" . $Identity . "] " . $Subject);
+ to=$EmailGeneralTo; cc=$EmailGeneralCc;
+ subject=[ $QuotedPrintable ("[" . $Identity . "] " . $Subject) ];
body=($Message . \
[ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \
[ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) };
@@ -1016,24 +1089,25 @@
# url encoding
:set UrlEncode do={
:local Input [ :tostr $1 ];
- :local Return "";
- :if ([ :len $Input ] > 0) do={
- :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~";
- :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27";
- "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E";
- "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D";
- "%7E" };
+ :if ([ :len $Input ] = 0) do={
+ :return "";
+ }
- :for I from=0 to=([ :len $Input ] - 1) do={
- :local Char [ :pick $Input $I ];
- :local Replace [ :find $Chars $Char ];
+ :local Return "";
+ :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~";
+ :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27";
+ "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F";
+ "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" };
- :if ([ :len $Replace ] > 0) do={
- :set Char ($Subs->$Replace);
- }
- :set Return ($Return . $Char);
+ :for I from=0 to=([ :len $Input ] - 1) do={
+ :local Char [ :pick $Input $I ];
+ :local Replace [ :find $Chars $Char ];
+
+ :if ([ :typeof $Replace ] = "num") do={
+ :set Char ($Subs->$Replace);
}
+ :set Return ($Return . $Char);
}
:return $Return;
@@ -1044,7 +1118,7 @@
:local Code [ :tostr $1 ];
:do {
- [ :parse (":local Validate do={ " . $Code . " }") ];
+ [ :parse (":local Validate do={\n" . $Code . "\n}") ];
} on-error={
:return false;
}
diff --git a/log-forward b/log-forward
index def04e6..8842c7c 100644
--- a/log-forward
+++ b/log-forward
@@ -15,9 +15,12 @@
:global LogForwardFilterMessage;
:global LogForwardLast;
:global LogForwardRateLimit;
+:global NotificationsWithSymbols;
+:global EscapeForRegEx;
:global IfThenElse;
:global LogPrintExit2;
+:global QuotedPrintable;
:global ScriptLock;
:global SendNotification;
:global SymbolForNotification;
@@ -37,18 +40,32 @@ $ScriptLock $0;
$WaitFullyConnected;
:local Count 0;
+:local Duplicates false;
:local Messages "";
:local MessageVal;
+:local MessageDups [ :toarray "" ];
-:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message~$LogForwardFilterMessage) ] do={
+:local LogForwardFilterLogForwarding ("^" . [ $EscapeForRegEx ("Error sending e-mail <" . \
+ [ $QuotedPrintable ("[" . $Identity . "] " . [ $SymbolForNotification "warning-sign" ] . \
+ "Log Forwarding") ] . ">:") ]);
+:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message="") \
+ !(message~$LogForwardFilterLogForwarding) !(message~$LogForwardFilterMessage) ] do={
:set MessageVal [ / log get $Message ];
:if ($LogForwardLast = ($MessageVal->".id")) do={
- :set Messages "";
:set Count 0;
+ :set Duplicates false;
+ :set Messages "";
+ :set MessageDups [ :toarray "" ];
} else={
- :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \
- [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message");
+ :local DupCount ($MessageDups->($MessageVal->"message"));
+ :if ($DupCount < 3) do={
+ :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \
+ $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message");
+ } else={
+ :set Duplicates true;
+ }
+ :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1);
:set Count ($Count + 1);
}
}
@@ -57,7 +74,8 @@ $WaitFullyConnected;
$SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \
("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \
"this message" ("these " . $Count . " messages") ] . " after " . \
- [ / system resource get uptime ] . " uptime.\n" . $Messages);
+ [ / system resource get uptime ] . " uptime." . [ $IfThenElse ($Duplicates = true) \
+ (" Multi-repeated messages have been skipped.") ] . "\n" . $Messages);
:set LogForwardRateLimit ($LogForwardRateLimit + 10);
:set LogForwardLast ($MessageVal->".id");