mirror of
https://github.com/eworm-de/routeros-scripts
synced 2024-05-14 08:04:19 +00:00
rename scripts and add file extension ".rsc"
No functional change for the user... The migration is done automatically.
This commit is contained in:
parent
1e6e0646e2
commit
a832fd04ef
125 changed files with 5622 additions and 5175 deletions
|
@ -19,7 +19,7 @@ Run the complete base installation:
|
||||||
/file/remove "letsencrypt-R3.pem";
|
/file/remove "letsencrypt-R3.pem";
|
||||||
:delay 1s;
|
:delay 1s;
|
||||||
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={
|
: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/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data");
|
||||||
};
|
};
|
||||||
/system/script { run global-config; run global-functions; };
|
/system/script { run global-config; run global-functions; };
|
||||||
/system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }";
|
/system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }";
|
||||||
|
|
14
Makefile
14
Makefile
|
@ -2,9 +2,9 @@
|
||||||
# template scripts -> final scripts
|
# template scripts -> final scripts
|
||||||
# markdown files -> html files
|
# markdown files -> html files
|
||||||
|
|
||||||
TEMPLATE = $(wildcard *.template)
|
TEMPLATE = $(wildcard *.template.rsc)
|
||||||
CAPSMAN = $(TEMPLATE:.template=.capsman)
|
CAPSMAN = $(TEMPLATE:.template.rsc=.capsman.rsc)
|
||||||
LOCAL = $(TEMPLATE:.template=.local)
|
LOCAL = $(TEMPLATE:.template.rsc=.local.rsc)
|
||||||
|
|
||||||
MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md)
|
MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md)
|
||||||
HTML = $(MARKDOWN:.md=.html)
|
HTML = $(MARKDOWN:.md=.html)
|
||||||
|
@ -14,13 +14,13 @@ all: $(CAPSMAN) $(LOCAL) $(HTML)
|
||||||
%.html: %.md Makefile
|
%.html: %.md Makefile
|
||||||
markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@
|
markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@
|
||||||
|
|
||||||
%.local: %.template Makefile
|
%.local.rsc: %.template.rsc Makefile
|
||||||
sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|$(suffix $@)|' \
|
sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|.local|' \
|
||||||
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
||||||
< $< > $@
|
< $< > $@
|
||||||
|
|
||||||
%.capsman: %.template Makefile
|
%.capsman.rsc: %.template.rsc Makefile
|
||||||
sed -e '/\/interface\/wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \
|
sed -e '/\/interface\/wireless/d' -e 's|%PATH%|caps-man|' -e 's|%TEMPL%|.capsman|' \
|
||||||
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
||||||
< $< > $@
|
< $< > $@
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ date and time is set correctly!
|
||||||
|
|
||||||
Now let's download the main scripts and add them in configuration on the fly.
|
Now let's download the main scripts and add them in configuration on the fly.
|
||||||
|
|
||||||
: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"); };
|
: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 . ".rsc") output=user as-value]->"data"); };
|
||||||
|
|
||||||
![screenshot: import scripts](README.d/04-import-scripts.avif)
|
![screenshot: import scripts](README.d/04-import-scripts.avif)
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ Editing configuration
|
||||||
|
|
||||||
The configuration needs to be tweaked for your needs. Edit
|
The configuration needs to be tweaked for your needs. Edit
|
||||||
`global-config-overlay`, copy relevant configuration from
|
`global-config-overlay`, copy relevant configuration from
|
||||||
[`global-config`](global-config) (the one without `-overlay`).
|
[`global-config`](global-config.rsc) (the one without `-overlay`).
|
||||||
Save changes and exit with `Ctrl-o`.
|
Save changes and exit with `Ctrl-o`.
|
||||||
|
|
||||||
/system/script/edit global-config-overlay source;
|
/system/script/edit global-config-overlay source;
|
||||||
|
@ -247,7 +247,7 @@ still use my scripts to manage and deploy yours, by specifying `base-url`
|
||||||
|
|
||||||
This will fetch and install a script `hello-world.rsc` from the given url:
|
This will fetch and install a script `hello-world.rsc` from the given url:
|
||||||
|
|
||||||
$ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/";
|
$ScriptInstallUpdate hello-world "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/";
|
||||||
|
|
||||||
![screenshot: install custom script](README.d/13-install-custom-script.avif)
|
![screenshot: install custom script](README.d/13-install-custom-script.avif)
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: accesslist-duplicates.capsman
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# print duplicate antries in wireless access list
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "accesslist-duplicates.capsman";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Read;
|
|
||||||
|
|
||||||
:local Seen ({});
|
|
||||||
:local Shown ({});
|
|
||||||
|
|
||||||
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
|
||||||
:local Mac [ /caps-man/access-list/get $AccList mac-address ];
|
|
||||||
:foreach SeenMac in=$Seen do={
|
|
||||||
:if ($SeenMac = $Mac) do={
|
|
||||||
:local Skip 0;
|
|
||||||
:foreach ShownMac in=$Shown do={
|
|
||||||
:if ($ShownMac = $Mac) do={ :set Skip 1; }
|
|
||||||
}
|
|
||||||
:if ($Skip = 0) do={
|
|
||||||
/caps-man/access-list/print where mac-address=$Mac;
|
|
||||||
:set Shown ($Shown, $Mac);
|
|
||||||
|
|
||||||
:put "\nNumeric id to remove, any key to skip!";
|
|
||||||
:local Remove [ :tonum [ $Read ] ];
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
|
||||||
:put ("Removing numeric id " . $Remove . "...\n");
|
|
||||||
/caps-man/access-list/remove $Remove;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set Seen ($Seen, $Mac);
|
|
||||||
}
|
|
||||||
|
|
42
accesslist-duplicates.capsman.rsc
Normal file
42
accesslist-duplicates.capsman.rsc
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: accesslist-duplicates.capsman
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# print duplicate antries in wireless access list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "accesslist-duplicates.capsman";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Read;
|
||||||
|
|
||||||
|
:local Seen ({});
|
||||||
|
:local Shown ({});
|
||||||
|
|
||||||
|
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
||||||
|
:local Mac [ /caps-man/access-list/get $AccList mac-address ];
|
||||||
|
:foreach SeenMac in=$Seen do={
|
||||||
|
:if ($SeenMac = $Mac) do={
|
||||||
|
:local Skip 0;
|
||||||
|
:foreach ShownMac in=$Shown do={
|
||||||
|
:if ($ShownMac = $Mac) do={ :set Skip 1; }
|
||||||
|
}
|
||||||
|
:if ($Skip = 0) do={
|
||||||
|
/caps-man/access-list/print where mac-address=$Mac;
|
||||||
|
:set Shown ($Shown, $Mac);
|
||||||
|
|
||||||
|
:put "\nNumeric id to remove, any key to skip!";
|
||||||
|
:local Remove [ :tonum [ $Read ] ];
|
||||||
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
:put ("Removing numeric id " . $Remove . "...\n");
|
||||||
|
/caps-man/access-list/remove $Remove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set Seen ($Seen, $Mac);
|
||||||
|
}
|
|
@ -1,42 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: accesslist-duplicates.local
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# print duplicate antries in wireless access list
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "accesslist-duplicates.local";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Read;
|
|
||||||
|
|
||||||
:local Seen ({});
|
|
||||||
:local Shown ({});
|
|
||||||
|
|
||||||
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
|
||||||
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
|
|
||||||
:foreach SeenMac in=$Seen do={
|
|
||||||
:if ($SeenMac = $Mac) do={
|
|
||||||
:local Skip 0;
|
|
||||||
:foreach ShownMac in=$Shown do={
|
|
||||||
:if ($ShownMac = $Mac) do={ :set Skip 1; }
|
|
||||||
}
|
|
||||||
:if ($Skip = 0) do={
|
|
||||||
/interface/wireless/access-list/print where mac-address=$Mac;
|
|
||||||
:set Shown ($Shown, $Mac);
|
|
||||||
|
|
||||||
:put "\nNumeric id to remove, any key to skip!";
|
|
||||||
:local Remove [ :tonum [ $Read ] ];
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
|
||||||
:put ("Removing numeric id " . $Remove . "...\n");
|
|
||||||
/interface/wireless/access-list/remove $Remove;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set Seen ($Seen, $Mac);
|
|
||||||
}
|
|
||||||
|
|
42
accesslist-duplicates.local.rsc
Normal file
42
accesslist-duplicates.local.rsc
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: accesslist-duplicates.local
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# print duplicate antries in wireless access list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "accesslist-duplicates.local";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Read;
|
||||||
|
|
||||||
|
:local Seen ({});
|
||||||
|
:local Shown ({});
|
||||||
|
|
||||||
|
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
||||||
|
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
|
||||||
|
:foreach SeenMac in=$Seen do={
|
||||||
|
:if ($SeenMac = $Mac) do={
|
||||||
|
:local Skip 0;
|
||||||
|
:foreach ShownMac in=$Shown do={
|
||||||
|
:if ($ShownMac = $Mac) do={ :set Skip 1; }
|
||||||
|
}
|
||||||
|
:if ($Skip = 0) do={
|
||||||
|
/interface/wireless/access-list/print where mac-address=$Mac;
|
||||||
|
:set Shown ($Shown, $Mac);
|
||||||
|
|
||||||
|
:put "\nNumeric id to remove, any key to skip!";
|
||||||
|
:local Remove [ :tonum [ $Read ] ];
|
||||||
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
:put ("Removing numeric id " . $Remove . "...\n");
|
||||||
|
/interface/wireless/access-list/remove $Remove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set Seen ($Seen, $Mac);
|
||||||
|
}
|
57
backup-cloud
57
backup-cloud
|
@ -1,58 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: backup-cloud
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: backup-script
|
# dummy for migration
|
||||||
#
|
|
||||||
# upload backup to MikroTik cloud
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md
|
|
||||||
|
|
||||||
:local 0 "backup-cloud";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global BackupPassword;
|
|
||||||
:global BackupRandomDelay;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global DeviceInfo;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global RandomDelay;
|
|
||||||
:global ScriptFromTerminal;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
|
||||||
$RandomDelay $BackupRandomDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
:do {
|
|
||||||
# we are not interested in output, but print is
|
|
||||||
# required to fetch information from cloud
|
|
||||||
/system/backup/cloud/print as-value;
|
|
||||||
:if ([ :len [ /system/backup/cloud/find ] ] > 0) do={
|
|
||||||
/system/backup/cloud/upload-file action=create-and-upload \
|
|
||||||
password=$BackupPassword replace=[ get ([ find ]->0) name ];
|
|
||||||
} else={
|
|
||||||
/system/backup/cloud/upload-file action=create-and-upload \
|
|
||||||
password=$BackupPassword;
|
|
||||||
}
|
|
||||||
:local Cloud [ /system/backup/cloud/get ([ find ]->0) ];
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \
|
|
||||||
message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \
|
|
||||||
[ $DeviceInfo ] . "\n\n" . \
|
|
||||||
"Name: " . $Cloud->"name" . "\n" . \
|
|
||||||
"Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \
|
|
||||||
"Download key: " . $Cloud->"secret-download-key"); silent=true });
|
|
||||||
} on-error={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \
|
|
||||||
message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) });
|
|
||||||
$LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true;
|
|
||||||
}
|
|
||||||
|
|
58
backup-cloud.rsc
Normal file
58
backup-cloud.rsc
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: backup-cloud
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: backup-script
|
||||||
|
#
|
||||||
|
# upload backup to MikroTik cloud
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md
|
||||||
|
|
||||||
|
:local 0 "backup-cloud";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global BackupPassword;
|
||||||
|
:global BackupRandomDelay;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global DeviceInfo;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global RandomDelay;
|
||||||
|
:global ScriptFromTerminal;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
||||||
|
$RandomDelay $BackupRandomDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
:do {
|
||||||
|
# we are not interested in output, but print is
|
||||||
|
# required to fetch information from cloud
|
||||||
|
/system/backup/cloud/print as-value;
|
||||||
|
:if ([ :len [ /system/backup/cloud/find ] ] > 0) do={
|
||||||
|
/system/backup/cloud/upload-file action=create-and-upload \
|
||||||
|
password=$BackupPassword replace=[ get ([ find ]->0) name ];
|
||||||
|
} else={
|
||||||
|
/system/backup/cloud/upload-file action=create-and-upload \
|
||||||
|
password=$BackupPassword;
|
||||||
|
}
|
||||||
|
:local Cloud [ /system/backup/cloud/get ([ find ]->0) ];
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \
|
||||||
|
message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \
|
||||||
|
[ $DeviceInfo ] . "\n\n" . \
|
||||||
|
"Name: " . $Cloud->"name" . "\n" . \
|
||||||
|
"Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \
|
||||||
|
"Download key: " . $Cloud->"secret-download-key"); silent=true });
|
||||||
|
} on-error={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \
|
||||||
|
message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) });
|
||||||
|
$LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true;
|
||||||
|
}
|
106
backup-email
106
backup-email
|
@ -1,107 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: backup-email
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: backup-script
|
# dummy for migration
|
||||||
#
|
|
||||||
# create and email backup and config file
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md
|
|
||||||
|
|
||||||
:local 0 "backup-email";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global BackupPassword;
|
|
||||||
:global BackupRandomDelay;
|
|
||||||
:global BackupSendBinary;
|
|
||||||
:global BackupSendExport;
|
|
||||||
:global BackupSendGlobalConfig;
|
|
||||||
:global Domain;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global DeviceInfo;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global MkDir;
|
|
||||||
:global RandomDelay;
|
|
||||||
:global ScriptFromTerminal;
|
|
||||||
:global SendEMail2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global WaitForFile;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ([ :typeof $SendEMail2 ] = "nothing") do={
|
|
||||||
$LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($BackupSendBinary != true && \
|
|
||||||
$BackupSendExport != true) do={
|
|
||||||
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
|
||||||
$RandomDelay $BackupRandomDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
# filename based on identity
|
|
||||||
:local DirName ("tmpfs/" . $0);
|
|
||||||
:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ];
|
|
||||||
:local FilePath ($DirName . "/" . $FileName);
|
|
||||||
:local BackupFile "none";
|
|
||||||
:local ExportFile "none";
|
|
||||||
:local ConfigFile "none";
|
|
||||||
:local Attach ({});
|
|
||||||
|
|
||||||
:if ([ $MkDir $DirName ] = false) do={
|
|
||||||
$LogPrintExit2 error $0 ("Failed creating directory!") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
# binary backup
|
|
||||||
:if ($BackupSendBinary = true) do={
|
|
||||||
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
|
||||||
$WaitForFile ($FilePath . ".backup");
|
|
||||||
:set BackupFile ($FileName . ".backup");
|
|
||||||
:set Attach ($Attach, ($FilePath . ".backup"));
|
|
||||||
}
|
|
||||||
|
|
||||||
# create configuration export
|
|
||||||
:if ($BackupSendExport = true) do={
|
|
||||||
/export terse show-sensitive file=$FilePath;
|
|
||||||
$WaitForFile ($FilePath . ".rsc");
|
|
||||||
:set ExportFile ($FileName . ".rsc");
|
|
||||||
:set Attach ($Attach, ($FilePath . ".rsc"));
|
|
||||||
}
|
|
||||||
|
|
||||||
# global-config-overlay
|
|
||||||
:if ($BackupSendGlobalConfig = true) do={
|
|
||||||
:execute script={ :put [ /system/script/get global-config-overlay source ]; } \
|
|
||||||
file=($FilePath . ".conf");
|
|
||||||
$WaitForFile ($FilePath . ".conf.txt");
|
|
||||||
:set ConfigFile ($FileName . ".conf.txt");
|
|
||||||
:set Attach ($Attach, ($FilePath . ".conf.txt"));
|
|
||||||
}
|
|
||||||
|
|
||||||
# send email with status and files
|
|
||||||
$SendEMail2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \
|
|
||||||
"Backup & Config"); \
|
|
||||||
message=("See attached files for backup and config export for " . \
|
|
||||||
$Identity . ".\n\n" . \
|
|
||||||
[ $DeviceInfo ] . "\n\n" . \
|
|
||||||
"Backup file: " . $BackupFile . "\n" . \
|
|
||||||
"Export file: " . $ExportFile . "\n" . \
|
|
||||||
"Config file: " . $ConfigFile); \
|
|
||||||
attach=$Attach; remove-attach=true });
|
|
||||||
|
|
||||||
# wait for the mail to be sent
|
|
||||||
:local I 0;
|
|
||||||
:while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={
|
|
||||||
:if ($I >= 120) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Files are still available, sending e-mail failed.") true;
|
|
||||||
}
|
|
||||||
:delay 1s;
|
|
||||||
:set I ($I + 1);
|
|
||||||
}
|
|
||||||
|
|
107
backup-email.rsc
Normal file
107
backup-email.rsc
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: backup-email
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: backup-script
|
||||||
|
#
|
||||||
|
# create and email backup and config file
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md
|
||||||
|
|
||||||
|
:local 0 "backup-email";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global BackupPassword;
|
||||||
|
:global BackupRandomDelay;
|
||||||
|
:global BackupSendBinary;
|
||||||
|
:global BackupSendExport;
|
||||||
|
:global BackupSendGlobalConfig;
|
||||||
|
:global Domain;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global DeviceInfo;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global MkDir;
|
||||||
|
:global RandomDelay;
|
||||||
|
:global ScriptFromTerminal;
|
||||||
|
:global SendEMail2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global WaitForFile;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ :typeof $SendEMail2 ] = "nothing") do={
|
||||||
|
$LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($BackupSendBinary != true && \
|
||||||
|
$BackupSendExport != true) do={
|
||||||
|
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
||||||
|
$RandomDelay $BackupRandomDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
# filename based on identity
|
||||||
|
:local DirName ("tmpfs/" . $0);
|
||||||
|
:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ];
|
||||||
|
:local FilePath ($DirName . "/" . $FileName);
|
||||||
|
:local BackupFile "none";
|
||||||
|
:local ExportFile "none";
|
||||||
|
:local ConfigFile "none";
|
||||||
|
:local Attach ({});
|
||||||
|
|
||||||
|
:if ([ $MkDir $DirName ] = false) do={
|
||||||
|
$LogPrintExit2 error $0 ("Failed creating directory!") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# binary backup
|
||||||
|
:if ($BackupSendBinary = true) do={
|
||||||
|
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
||||||
|
$WaitForFile ($FilePath . ".backup");
|
||||||
|
:set BackupFile ($FileName . ".backup");
|
||||||
|
:set Attach ($Attach, ($FilePath . ".backup"));
|
||||||
|
}
|
||||||
|
|
||||||
|
# create configuration export
|
||||||
|
:if ($BackupSendExport = true) do={
|
||||||
|
/export terse show-sensitive file=$FilePath;
|
||||||
|
$WaitForFile ($FilePath . ".rsc");
|
||||||
|
:set ExportFile ($FileName . ".rsc");
|
||||||
|
:set Attach ($Attach, ($FilePath . ".rsc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
# global-config-overlay
|
||||||
|
:if ($BackupSendGlobalConfig = true) do={
|
||||||
|
:execute script={ :put [ /system/script/get global-config-overlay source ]; } \
|
||||||
|
file=($FilePath . ".conf");
|
||||||
|
$WaitForFile ($FilePath . ".conf.txt");
|
||||||
|
:set ConfigFile ($FileName . ".conf.txt");
|
||||||
|
:set Attach ($Attach, ($FilePath . ".conf.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
# send email with status and files
|
||||||
|
$SendEMail2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \
|
||||||
|
"Backup & Config"); \
|
||||||
|
message=("See attached files for backup and config export for " . \
|
||||||
|
$Identity . ".\n\n" . \
|
||||||
|
[ $DeviceInfo ] . "\n\n" . \
|
||||||
|
"Backup file: " . $BackupFile . "\n" . \
|
||||||
|
"Export file: " . $ExportFile . "\n" . \
|
||||||
|
"Config file: " . $ConfigFile); \
|
||||||
|
attach=$Attach; remove-attach=true });
|
||||||
|
|
||||||
|
# wait for the mail to be sent
|
||||||
|
:local I 0;
|
||||||
|
:while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={
|
||||||
|
:if ($I >= 120) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Files are still available, sending e-mail failed.") true;
|
||||||
|
}
|
||||||
|
:delay 1s;
|
||||||
|
:set I ($I + 1);
|
||||||
|
}
|
|
@ -1,36 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: backup-partition
|
|
||||||
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: backup-script
|
# dummy for migration
|
||||||
#
|
|
||||||
# save configuration to fallback partition
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md
|
|
||||||
|
|
||||||
:local 0 "backup-partition";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:if ([ :len [ /partitions/find ] ] < 2) do={
|
|
||||||
$LogPrintExit2 error $0 ("Device does not have a fallback partition.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local ActiveRunning [ /partitions/find where active running ];
|
|
||||||
|
|
||||||
:if ([ :len $ActiveRunning ] < 1) do={
|
|
||||||
$LogPrintExit2 error $0 ("Device is not running from active partition.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local ActiveRunningVar [ /partitions/get $ActiveRunning ];
|
|
||||||
|
|
||||||
:do {
|
|
||||||
/partitions/save-config-to ($ActiveRunningVar->"fallback-to");
|
|
||||||
$LogPrintExit2 info $0 ("Saved configuration to partition '" . \
|
|
||||||
($ActiveRunningVar->"fallback-to") . "'.") false;
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \
|
|
||||||
($ActiveRunningVar->"fallback-to") . "'!") true;
|
|
||||||
}
|
|
||||||
|
|
36
backup-partition.rsc
Normal file
36
backup-partition.rsc
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: backup-partition
|
||||||
|
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: backup-script
|
||||||
|
#
|
||||||
|
# save configuration to fallback partition
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md
|
||||||
|
|
||||||
|
:local 0 "backup-partition";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:if ([ :len [ /partitions/find ] ] < 2) do={
|
||||||
|
$LogPrintExit2 error $0 ("Device does not have a fallback partition.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local ActiveRunning [ /partitions/find where active running ];
|
||||||
|
|
||||||
|
:if ([ :len $ActiveRunning ] < 1) do={
|
||||||
|
$LogPrintExit2 error $0 ("Device is not running from active partition.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local ActiveRunningVar [ /partitions/get $ActiveRunning ];
|
||||||
|
|
||||||
|
:do {
|
||||||
|
/partitions/save-config-to ($ActiveRunningVar->"fallback-to");
|
||||||
|
$LogPrintExit2 info $0 ("Saved configuration to partition '" . \
|
||||||
|
($ActiveRunningVar->"fallback-to") . "'.") false;
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \
|
||||||
|
($ActiveRunningVar->"fallback-to") . "'!") true;
|
||||||
|
}
|
128
backup-upload
128
backup-upload
|
@ -1,129 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: backup-upload
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: backup-script
|
# dummy for migration
|
||||||
#
|
|
||||||
# create and upload backup and config file
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md
|
|
||||||
|
|
||||||
:local 0 "backup-upload";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global BackupPassword;
|
|
||||||
:global BackupRandomDelay;
|
|
||||||
:global BackupSendBinary;
|
|
||||||
:global BackupSendExport;
|
|
||||||
:global BackupSendGlobalConfig;
|
|
||||||
:global BackupUploadPass;
|
|
||||||
:global BackupUploadUrl;
|
|
||||||
:global BackupUploadUser;
|
|
||||||
:global Domain;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global DeviceInfo;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global MkDir;
|
|
||||||
:global RandomDelay;
|
|
||||||
:global ScriptFromTerminal;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global WaitForFile;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ($BackupSendBinary != true && \
|
|
||||||
$BackupSendExport != true) do={
|
|
||||||
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
|
||||||
$RandomDelay $BackupRandomDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
# filename based on identity
|
|
||||||
:local DirName ("tmpfs/" . $0);
|
|
||||||
:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ];
|
|
||||||
:local FilePath ($DirName . "/" . $FileName);
|
|
||||||
:local BackupFile "none";
|
|
||||||
:local ExportFile "none";
|
|
||||||
:local ConfigFile "none";
|
|
||||||
:local Failed 0;
|
|
||||||
|
|
||||||
:if ([ $MkDir $DirName ] = false) do={
|
|
||||||
$LogPrintExit2 error $0 ("Failed creating directory!") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
# binary backup
|
|
||||||
:if ($BackupSendBinary = true) do={
|
|
||||||
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
|
||||||
$WaitForFile ($FilePath . ".backup");
|
|
||||||
|
|
||||||
:do {
|
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \
|
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup");
|
|
||||||
:set BackupFile ($FileName . ".backup");
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 error $0 ("Uploading backup file failed!") false;
|
|
||||||
:set BackupFile "failed";
|
|
||||||
:set Failed 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/file/remove ($FilePath . ".backup");
|
|
||||||
}
|
|
||||||
|
|
||||||
# create configuration export
|
|
||||||
:if ($BackupSendExport = true) do={
|
|
||||||
/export terse show-sensitive file=$FilePath;
|
|
||||||
$WaitForFile ($FilePath . ".rsc");
|
|
||||||
|
|
||||||
:do {
|
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \
|
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc");
|
|
||||||
:set ExportFile ($FileName . ".rsc");
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 error $0 ("Uploading configuration export failed!") false;
|
|
||||||
:set ExportFile "failed";
|
|
||||||
:set Failed 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/file/remove ($FilePath . ".rsc");
|
|
||||||
}
|
|
||||||
|
|
||||||
# global-config-overlay
|
|
||||||
:if ($BackupSendGlobalConfig = true) do={
|
|
||||||
:execute script={ :put [ /system/script/get global-config-overlay source ]; } \
|
|
||||||
file=($FilePath . ".conf");
|
|
||||||
$WaitForFile ($FilePath . ".conf.txt");
|
|
||||||
|
|
||||||
:do {
|
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \
|
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt");
|
|
||||||
:set ConfigFile ($FileName . ".conf");
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false;
|
|
||||||
:set ConfigFile "failed";
|
|
||||||
:set Failed 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/file/remove ($FilePath . ".conf.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=[ $IfThenElse ($Failed > 0) \
|
|
||||||
([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \
|
|
||||||
([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \
|
|
||||||
message=("Backup and config export upload for " . $Identity . ".\n\n" . \
|
|
||||||
[ $DeviceInfo ] . "\n\n" . \
|
|
||||||
"Backup file: " . $BackupFile . "\n" . \
|
|
||||||
"Export file: " . $ExportFile . "\n" . \
|
|
||||||
"Config file: " . $ConfigFile); silent=true });
|
|
||||||
|
|
||||||
:if ($Failed = 1) do={
|
|
||||||
:error "An error occured!";
|
|
||||||
}
|
|
||||||
|
|
129
backup-upload.rsc
Normal file
129
backup-upload.rsc
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: backup-upload
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: backup-script
|
||||||
|
#
|
||||||
|
# create and upload backup and config file
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md
|
||||||
|
|
||||||
|
:local 0 "backup-upload";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global BackupPassword;
|
||||||
|
:global BackupRandomDelay;
|
||||||
|
:global BackupSendBinary;
|
||||||
|
:global BackupSendExport;
|
||||||
|
:global BackupSendGlobalConfig;
|
||||||
|
:global BackupUploadPass;
|
||||||
|
:global BackupUploadUrl;
|
||||||
|
:global BackupUploadUser;
|
||||||
|
:global Domain;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global DeviceInfo;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global MkDir;
|
||||||
|
:global RandomDelay;
|
||||||
|
:global ScriptFromTerminal;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global WaitForFile;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ($BackupSendBinary != true && \
|
||||||
|
$BackupSendExport != true) do={
|
||||||
|
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
|
||||||
|
$RandomDelay $BackupRandomDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
# filename based on identity
|
||||||
|
:local DirName ("tmpfs/" . $0);
|
||||||
|
:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ];
|
||||||
|
:local FilePath ($DirName . "/" . $FileName);
|
||||||
|
:local BackupFile "none";
|
||||||
|
:local ExportFile "none";
|
||||||
|
:local ConfigFile "none";
|
||||||
|
:local Failed 0;
|
||||||
|
|
||||||
|
:if ([ $MkDir $DirName ] = false) do={
|
||||||
|
$LogPrintExit2 error $0 ("Failed creating directory!") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# binary backup
|
||||||
|
:if ($BackupSendBinary = true) do={
|
||||||
|
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
||||||
|
$WaitForFile ($FilePath . ".backup");
|
||||||
|
|
||||||
|
:do {
|
||||||
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \
|
||||||
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup");
|
||||||
|
:set BackupFile ($FileName . ".backup");
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 error $0 ("Uploading backup file failed!") false;
|
||||||
|
:set BackupFile "failed";
|
||||||
|
:set Failed 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/file/remove ($FilePath . ".backup");
|
||||||
|
}
|
||||||
|
|
||||||
|
# create configuration export
|
||||||
|
:if ($BackupSendExport = true) do={
|
||||||
|
/export terse show-sensitive file=$FilePath;
|
||||||
|
$WaitForFile ($FilePath . ".rsc");
|
||||||
|
|
||||||
|
:do {
|
||||||
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \
|
||||||
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc");
|
||||||
|
:set ExportFile ($FileName . ".rsc");
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 error $0 ("Uploading configuration export failed!") false;
|
||||||
|
:set ExportFile "failed";
|
||||||
|
:set Failed 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/file/remove ($FilePath . ".rsc");
|
||||||
|
}
|
||||||
|
|
||||||
|
# global-config-overlay
|
||||||
|
:if ($BackupSendGlobalConfig = true) do={
|
||||||
|
:execute script={ :put [ /system/script/get global-config-overlay source ]; } \
|
||||||
|
file=($FilePath . ".conf");
|
||||||
|
$WaitForFile ($FilePath . ".conf.txt");
|
||||||
|
|
||||||
|
:do {
|
||||||
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \
|
||||||
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf.txt");
|
||||||
|
:set ConfigFile ($FileName . ".conf");
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false;
|
||||||
|
:set ConfigFile "failed";
|
||||||
|
:set Failed 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/file/remove ($FilePath . ".conf.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=[ $IfThenElse ($Failed > 0) \
|
||||||
|
([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \
|
||||||
|
([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \
|
||||||
|
message=("Backup and config export upload for " . $Identity . ".\n\n" . \
|
||||||
|
[ $DeviceInfo ] . "\n\n" . \
|
||||||
|
"Backup file: " . $BackupFile . "\n" . \
|
||||||
|
"Export file: " . $ExportFile . "\n" . \
|
||||||
|
"Config file: " . $ConfigFile); silent=true });
|
||||||
|
|
||||||
|
:if ($Failed = 1) do={
|
||||||
|
:error "An error occured!";
|
||||||
|
}
|
|
@ -1,86 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: capsman-download-packages
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# Michael Gisbers <michael@gisbers.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# download and cleanup packages for CAP installation from CAPsMAN
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md
|
|
||||||
|
|
||||||
:local 0 "capsman-download-packages";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global CleanFilePath;
|
|
||||||
:global DownloadPackage;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global MkDir;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ];
|
|
||||||
:local InstalledVersion [ /system/package/update/get installed-version ];
|
|
||||||
:local Updated false;
|
|
||||||
|
|
||||||
:if ([ :len $PackagePath ] = 0) do={
|
|
||||||
$LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
|
|
||||||
:if ([ $MkDir $PackagePath ] = false) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \
|
|
||||||
$PackagePath . ") failed!") true;
|
|
||||||
}
|
|
||||||
$LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \
|
|
||||||
"). Please place your packages!") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Package in=[ /file/find where type=package \
|
|
||||||
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
|
||||||
:local File [ /file/get $Package ];
|
|
||||||
:if ($File->"package-architecture" = "mips") do={
|
|
||||||
:set ($File->"package-architecture") "mipsbe";
|
|
||||||
}
|
|
||||||
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
|
||||||
($File->"package-architecture") $PackagePath ] = true) do={
|
|
||||||
:set Updated true;
|
|
||||||
/file/remove $Package;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \
|
|
||||||
!(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \
|
|
||||||
"Probably can not download packages automatically.") false;
|
|
||||||
} else={
|
|
||||||
:if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={
|
|
||||||
$LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false;
|
|
||||||
:delay 2m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \
|
|
||||||
message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \
|
|
||||||
"-.*\\.npk', no such file") ] do={
|
|
||||||
:local Message [ /log/get $Log message ];
|
|
||||||
:local Package [ :pick $Message \
|
|
||||||
([ :find $Message "'" ] + 1) \
|
|
||||||
[ :find $Message ("-" . $InstalledVersion . "-") ] ];
|
|
||||||
:local Arch [ :pick $Message \
|
|
||||||
([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \
|
|
||||||
[ :find $Message ".npk" ] ];
|
|
||||||
:if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={
|
|
||||||
:set Updated true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($Updated = true) do={
|
|
||||||
:if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={
|
|
||||||
/system/script/run capsman-rolling-upgrade;
|
|
||||||
} else={
|
|
||||||
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
86
capsman-download-packages.rsc
Normal file
86
capsman-download-packages.rsc
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: capsman-download-packages
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# Michael Gisbers <michael@gisbers.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# download and cleanup packages for CAP installation from CAPsMAN
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md
|
||||||
|
|
||||||
|
:local 0 "capsman-download-packages";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global CleanFilePath;
|
||||||
|
:global DownloadPackage;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global MkDir;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ];
|
||||||
|
:local InstalledVersion [ /system/package/update/get installed-version ];
|
||||||
|
:local Updated false;
|
||||||
|
|
||||||
|
:if ([ :len $PackagePath ] = 0) do={
|
||||||
|
$LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
|
||||||
|
:if ([ $MkDir $PackagePath ] = false) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \
|
||||||
|
$PackagePath . ") failed!") true;
|
||||||
|
}
|
||||||
|
$LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \
|
||||||
|
"). Please place your packages!") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Package in=[ /file/find where type=package \
|
||||||
|
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
||||||
|
:local File [ /file/get $Package ];
|
||||||
|
:if ($File->"package-architecture" = "mips") do={
|
||||||
|
:set ($File->"package-architecture") "mipsbe";
|
||||||
|
}
|
||||||
|
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
||||||
|
($File->"package-architecture") $PackagePath ] = true) do={
|
||||||
|
:set Updated true;
|
||||||
|
/file/remove $Package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \
|
||||||
|
!(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \
|
||||||
|
"Probably can not download packages automatically.") false;
|
||||||
|
} else={
|
||||||
|
:if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={
|
||||||
|
$LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false;
|
||||||
|
:delay 2m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \
|
||||||
|
message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \
|
||||||
|
"-.*\\.npk', no such file") ] do={
|
||||||
|
:local Message [ /log/get $Log message ];
|
||||||
|
:local Package [ :pick $Message \
|
||||||
|
([ :find $Message "'" ] + 1) \
|
||||||
|
[ :find $Message ("-" . $InstalledVersion . "-") ] ];
|
||||||
|
:local Arch [ :pick $Message \
|
||||||
|
([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \
|
||||||
|
[ :find $Message ".npk" ] ];
|
||||||
|
:if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={
|
||||||
|
:set Updated true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($Updated = true) do={
|
||||||
|
:if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={
|
||||||
|
/system/script/run capsman-rolling-upgrade;
|
||||||
|
} else={
|
||||||
|
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,36 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: capsman-rolling-upgrade
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# Michael Gisbers <michael@gisbers.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# upgrade CAPs one after another
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md
|
|
||||||
|
|
||||||
:local 0 "capsman-rolling-upgrade";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
|
|
||||||
:local InstalledVersion [ /system/package/update/get installed-version ];
|
|
||||||
|
|
||||||
:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ];
|
|
||||||
:if ($RemoteCapCount > 0) do={
|
|
||||||
:local Delay (600 / $RemoteCapCount);
|
|
||||||
:if ($Delay > 120) do={ :set Delay 120; }
|
|
||||||
:foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={
|
|
||||||
:local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ];
|
|
||||||
:if ([ :len $RemoteCapVal ] > 1) do={
|
|
||||||
$LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \
|
|
||||||
" (" . $RemoteCapVal->"identity" . ")...") false;
|
|
||||||
/caps-man/remote-cap/upgrade $RemoteCap;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false;
|
|
||||||
}
|
|
||||||
:delay ($Delay . "s");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
36
capsman-rolling-upgrade.rsc
Normal file
36
capsman-rolling-upgrade.rsc
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: capsman-rolling-upgrade
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# Michael Gisbers <michael@gisbers.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# upgrade CAPs one after another
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md
|
||||||
|
|
||||||
|
:local 0 "capsman-rolling-upgrade";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
|
||||||
|
:local InstalledVersion [ /system/package/update/get installed-version ];
|
||||||
|
|
||||||
|
:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ];
|
||||||
|
:if ($RemoteCapCount > 0) do={
|
||||||
|
:local Delay (600 / $RemoteCapCount);
|
||||||
|
:if ($Delay > 120) do={ :set Delay 120; }
|
||||||
|
:foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={
|
||||||
|
:local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ];
|
||||||
|
:if ([ :len $RemoteCapVal ] > 1) do={
|
||||||
|
$LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \
|
||||||
|
" (" . $RemoteCapVal->"identity" . ")...") false;
|
||||||
|
/caps-man/remote-cap/upgrade $RemoteCap;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false;
|
||||||
|
}
|
||||||
|
:delay ($Delay . "s");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: certificate-renew-issued
|
|
||||||
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# renew locally issued certificates
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md
|
|
||||||
|
|
||||||
:local 0 "certificate-renew-issued";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global CertIssuedExportPass;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global MkDir;
|
|
||||||
|
|
||||||
:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={
|
|
||||||
:local CertVal [ /certificate/get $Cert ];
|
|
||||||
/certificate/issued-revoke $Cert;
|
|
||||||
/certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert;
|
|
||||||
/certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \
|
|
||||||
key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name");
|
|
||||||
/certificate/sign ($CertVal->"name") ca=($CertVal->"ca");
|
|
||||||
:if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={
|
|
||||||
:if ([ $MkDir "cert-issued" ] = true) do={
|
|
||||||
/certificate/export-certificate ($CertVal->"name") type=pkcs12 \
|
|
||||||
file-name=("cert-issued/" . $CertVal->"common-name") \
|
|
||||||
export-passphrase=($CertIssuedExportPass->($CertVal->"common-name"));
|
|
||||||
$LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \
|
|
||||||
"\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
38
certificate-renew-issued.rsc
Normal file
38
certificate-renew-issued.rsc
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: certificate-renew-issued
|
||||||
|
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# renew locally issued certificates
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md
|
||||||
|
|
||||||
|
:local 0 "certificate-renew-issued";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global CertIssuedExportPass;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global MkDir;
|
||||||
|
|
||||||
|
:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={
|
||||||
|
:local CertVal [ /certificate/get $Cert ];
|
||||||
|
/certificate/issued-revoke $Cert;
|
||||||
|
/certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert;
|
||||||
|
/certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \
|
||||||
|
key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name");
|
||||||
|
/certificate/sign ($CertVal->"name") ca=($CertVal->"ca");
|
||||||
|
:if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={
|
||||||
|
:if ([ $MkDir "cert-issued" ] = true) do={
|
||||||
|
/certificate/export-certificate ($CertVal->"name") type=pkcs12 \
|
||||||
|
file-name=("cert-issued/" . $CertVal->"common-name") \
|
||||||
|
export-passphrase=($CertIssuedExportPass->($CertVal->"common-name"));
|
||||||
|
$LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \
|
||||||
|
"\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,138 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: check-certificates
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# check for certificate validity
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md
|
|
||||||
|
|
||||||
:local 0 "check-certificates";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global CertRenewPass;
|
|
||||||
:global CertRenewTime;
|
|
||||||
:global CertRenewUrl;
|
|
||||||
:global CertWarnTime;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global CertificateAvailable
|
|
||||||
:global CertificateNameByCN;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global UrlEncode;
|
|
||||||
:global WaitForFile;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
:local FormatExpire do={
|
|
||||||
:global CharacterReplace;
|
|
||||||
:return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ];
|
|
||||||
}
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={
|
|
||||||
:local CertVal [ /certificate/get $Cert ];
|
|
||||||
|
|
||||||
:do {
|
|
||||||
: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);
|
|
||||||
:do {
|
|
||||||
/tool/fetch check-certificate=yes-without-crl \
|
|
||||||
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
|
|
||||||
$WaitForFile $CertFileName;
|
|
||||||
|
|
||||||
:local DecryptionFailed true;
|
|
||||||
:foreach PassPhrase in=$CertRenewPass do={
|
|
||||||
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
|
|
||||||
:if ($Result->"decryption-failures" = 0) do={
|
|
||||||
:set DecryptionFailed false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/file/remove [ find where name=$CertFileName ];
|
|
||||||
|
|
||||||
:if ($DecryptionFailed = true) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={
|
|
||||||
$CertificateNameByCN [ /certificate/get $CertInChain common-name ];
|
|
||||||
}
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ];
|
|
||||||
:local CertNewVal [ /certificate/get $CertNew ];
|
|
||||||
|
|
||||||
:if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={
|
|
||||||
$LogPrintExit2 warning $0 ("The certificate chain is not available!") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($Cert != $CertNew) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false;
|
|
||||||
|
|
||||||
:if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={
|
|
||||||
/certificate/remove $CertNew;
|
|
||||||
$LogPrintExit2 warning $0 ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ];
|
|
||||||
|
|
||||||
/ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ];
|
|
||||||
/ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ];
|
|
||||||
|
|
||||||
/ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ];
|
|
||||||
|
|
||||||
/certificate/remove $Cert;
|
|
||||||
/certificate/set $CertNew name=($CertVal->"name");
|
|
||||||
}
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \
|
|
||||||
message=("A certificate on " . $Identity . " has been renewed.\n\n" . \
|
|
||||||
"Name: " . ($CertVal->"name") . "\n" . \
|
|
||||||
"CommonName: " . ($CertNewVal->"common-name") . "\n" . \
|
|
||||||
"Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \
|
|
||||||
"Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \
|
|
||||||
"Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \
|
|
||||||
"Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \
|
|
||||||
"Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true });
|
|
||||||
$LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false;
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \
|
|
||||||
expires-after<$CertWarnTime !(fingerprint=[]) ] do={
|
|
||||||
:local CertVal [ /certificate/get $Cert ];
|
|
||||||
|
|
||||||
:if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false;
|
|
||||||
} else={
|
|
||||||
:local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ];
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \
|
|
||||||
message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \
|
|
||||||
"Name: " . ($CertVal->"name") . "\n" . \
|
|
||||||
"CommonName: " . ($CertVal->"common-name") . "\n" . \
|
|
||||||
"Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \
|
|
||||||
"Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \
|
|
||||||
"Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \
|
|
||||||
"Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \
|
|
||||||
"Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) });
|
|
||||||
$LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \
|
|
||||||
", it is invalid after " . ($CertVal->"invalid-after") . ".") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
138
check-certificates.rsc
Normal file
138
check-certificates.rsc
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: check-certificates
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# check for certificate validity
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md
|
||||||
|
|
||||||
|
:local 0 "check-certificates";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global CertRenewPass;
|
||||||
|
:global CertRenewTime;
|
||||||
|
:global CertRenewUrl;
|
||||||
|
:global CertWarnTime;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global CertificateAvailable
|
||||||
|
:global CertificateNameByCN;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global UrlEncode;
|
||||||
|
:global WaitForFile;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
:local FormatExpire do={
|
||||||
|
:global CharacterReplace;
|
||||||
|
:return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={
|
||||||
|
:local CertVal [ /certificate/get $Cert ];
|
||||||
|
|
||||||
|
:do {
|
||||||
|
: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);
|
||||||
|
:do {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl \
|
||||||
|
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
|
||||||
|
$WaitForFile $CertFileName;
|
||||||
|
|
||||||
|
:local DecryptionFailed true;
|
||||||
|
:foreach PassPhrase in=$CertRenewPass do={
|
||||||
|
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
|
||||||
|
:if ($Result->"decryption-failures" = 0) do={
|
||||||
|
:set DecryptionFailed false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/file/remove [ find where name=$CertFileName ];
|
||||||
|
|
||||||
|
:if ($DecryptionFailed = true) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Decryption failed for certificate file " . $CertFileName) false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach CertInChain in=[ /certificate/find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={
|
||||||
|
$CertificateNameByCN [ /certificate/get $CertInChain common-name ];
|
||||||
|
}
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ];
|
||||||
|
:local CertNewVal [ /certificate/get $CertNew ];
|
||||||
|
|
||||||
|
:if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={
|
||||||
|
$LogPrintExit2 warning $0 ("The certificate chain is not available!") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($Cert != $CertNew) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false;
|
||||||
|
|
||||||
|
:if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={
|
||||||
|
/certificate/remove $CertNew;
|
||||||
|
$LogPrintExit2 warning $0 ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ];
|
||||||
|
|
||||||
|
/ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ];
|
||||||
|
/ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ];
|
||||||
|
|
||||||
|
/ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ];
|
||||||
|
|
||||||
|
/certificate/remove $Cert;
|
||||||
|
/certificate/set $CertNew name=($CertVal->"name");
|
||||||
|
}
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \
|
||||||
|
message=("A certificate on " . $Identity . " has been renewed.\n\n" . \
|
||||||
|
"Name: " . ($CertVal->"name") . "\n" . \
|
||||||
|
"CommonName: " . ($CertNewVal->"common-name") . "\n" . \
|
||||||
|
"Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \
|
||||||
|
"Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \
|
||||||
|
"Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \
|
||||||
|
"Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \
|
||||||
|
"Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true });
|
||||||
|
$LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false;
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \
|
||||||
|
expires-after<$CertWarnTime !(fingerprint=[]) ] do={
|
||||||
|
:local CertVal [ /certificate/get $Cert ];
|
||||||
|
|
||||||
|
:if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false;
|
||||||
|
} else={
|
||||||
|
:local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ];
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \
|
||||||
|
message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \
|
||||||
|
"Name: " . ($CertVal->"name") . "\n" . \
|
||||||
|
"CommonName: " . ($CertVal->"common-name") . "\n" . \
|
||||||
|
"Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \
|
||||||
|
"Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \
|
||||||
|
"Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \
|
||||||
|
"Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \
|
||||||
|
"Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) });
|
||||||
|
$LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \
|
||||||
|
", it is invalid after " . ($CertVal->"invalid-after") . ".") false;
|
||||||
|
}
|
||||||
|
}
|
166
check-health
166
check-health
|
@ -1,167 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: check-health
|
|
||||||
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# check for RouterOS health state
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md
|
|
||||||
|
|
||||||
:local 0 "check-health";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global CheckHealthCPUUtilization;
|
|
||||||
:global CheckHealthCPUUtilizationNotified;
|
|
||||||
:global CheckHealthFreeRAMNotified;
|
|
||||||
:global CheckHealthLast;
|
|
||||||
:global CheckHealthTemperature;
|
|
||||||
:global CheckHealthTemperatureDeviation;
|
|
||||||
:global CheckHealthTemperatureNotified;
|
|
||||||
:global CheckHealthVoltageLow;
|
|
||||||
:global CheckHealthVoltagePercent;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
:local TempToNum do={
|
|
||||||
:global CharacterReplace;
|
|
||||||
:local T [ :toarray [ $CharacterReplace $1 "." "," ] ];
|
|
||||||
:return ($T->0 * 10 + $T->1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
|
|
||||||
:local Resource [ /system/resource/get ];
|
|
||||||
|
|
||||||
:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5);
|
|
||||||
:if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \
|
|
||||||
message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") });
|
|
||||||
:set CheckHealthCPUUtilizationNotified true;
|
|
||||||
}
|
|
||||||
:if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \
|
|
||||||
message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") });
|
|
||||||
:set CheckHealthCPUUtilizationNotified false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory");
|
|
||||||
:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \
|
|
||||||
message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \
|
|
||||||
($Resource->"free-memory" / 1024 / 1024) . "MiB)!") });
|
|
||||||
:set CheckHealthFreeRAMNotified true;
|
|
||||||
}
|
|
||||||
:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \
|
|
||||||
message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \
|
|
||||||
($Resource->"free-memory" / 1024 / 1024) . "MiB).") });
|
|
||||||
:set CheckHealthFreeRAMNotified false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len [ /system/health/find ] ] = 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Your device does not provide any health values.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :typeof $CheckHealthLast ] != "array") do={
|
|
||||||
:set CheckHealthLast ({});
|
|
||||||
}
|
|
||||||
:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={
|
|
||||||
:set CheckHealthTemperatureNotified ({});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
:foreach Voltage in=[ /system/health/find where type="V" ] do={
|
|
||||||
:local Name [ /system/health/get $Voltage name ];
|
|
||||||
:local Value [ /system/health/get $Voltage value ];
|
|
||||||
|
|
||||||
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
|
||||||
:local NumCurr [ $TempToNum $Value ];
|
|
||||||
:local NumLast [ $TempToNum ($CheckHealthLast->$Name) ];
|
|
||||||
|
|
||||||
:if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \
|
|
||||||
$NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \
|
|
||||||
$NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \
|
|
||||||
message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \
|
|
||||||
"old value: " . ($CheckHealthLast->$Name) . " V\n" . \
|
|
||||||
"new value: " . $Value . " V") });
|
|
||||||
} else={
|
|
||||||
:if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \
|
|
||||||
message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") });
|
|
||||||
}
|
|
||||||
:if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \
|
|
||||||
message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set ($CheckHealthLast->$Name) $Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={
|
|
||||||
:local Name [ /system/health/get $PSU name ];
|
|
||||||
:local Value [ /system/health/get $PSU value ];
|
|
||||||
|
|
||||||
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
|
||||||
:if ($CheckHealthLast->$Name = "ok" && \
|
|
||||||
$Value != "ok") do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \
|
|
||||||
message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") });
|
|
||||||
}
|
|
||||||
:if ($CheckHealthLast->$Name != "ok" && \
|
|
||||||
$Value = "ok") do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
|
|
||||||
message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set ($CheckHealthLast->$Name) $Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Temperature in=[ /system/health/find where type="C" ] do={
|
|
||||||
:local Name [ /system/health/get $Temperature name ];
|
|
||||||
:local Value [ /system/health/get $Temperature value ];
|
|
||||||
|
|
||||||
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
|
||||||
:if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={
|
|
||||||
$LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false;
|
|
||||||
:set ($CheckHealthTemperature->$Name) 50;
|
|
||||||
}
|
|
||||||
:local Validate [ /system/health/get [ find where name=$Name ] value ];
|
|
||||||
:while ($Value != $Validate) do={
|
|
||||||
:set Value $Validate;
|
|
||||||
:set Validate [ /system/health/get [ find where name=$Name ] value ];
|
|
||||||
}
|
|
||||||
:if ($Value > $CheckHealthTemperature->$Name && \
|
|
||||||
$CheckHealthTemperatureNotified->$Name != true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \
|
|
||||||
message=("The " . $Name . " on " . $Identity . " is above threshold: " . \
|
|
||||||
$Value . "\C2\B0" . "C") });
|
|
||||||
:set ($CheckHealthTemperatureNotified->$Name) true;
|
|
||||||
}
|
|
||||||
:if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \
|
|
||||||
$CheckHealthTemperatureNotified->$Name = true) do={
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
|
|
||||||
message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \
|
|
||||||
$Value . "\C2\B0" . "C") });
|
|
||||||
:set ($CheckHealthTemperatureNotified->$Name) false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set ($CheckHealthLast->$Name) $Value;
|
|
||||||
}
|
|
||||||
|
|
167
check-health.rsc
Normal file
167
check-health.rsc
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: check-health
|
||||||
|
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# check for RouterOS health state
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md
|
||||||
|
|
||||||
|
:local 0 "check-health";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global CheckHealthCPUUtilization;
|
||||||
|
:global CheckHealthCPUUtilizationNotified;
|
||||||
|
:global CheckHealthFreeRAMNotified;
|
||||||
|
:global CheckHealthLast;
|
||||||
|
:global CheckHealthTemperature;
|
||||||
|
:global CheckHealthTemperatureDeviation;
|
||||||
|
:global CheckHealthTemperatureNotified;
|
||||||
|
:global CheckHealthVoltageLow;
|
||||||
|
:global CheckHealthVoltagePercent;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
:local TempToNum do={
|
||||||
|
:global CharacterReplace;
|
||||||
|
:local T [ :toarray [ $CharacterReplace $1 "." "," ] ];
|
||||||
|
:return ($T->0 * 10 + $T->1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
|
||||||
|
:local Resource [ /system/resource/get ];
|
||||||
|
|
||||||
|
:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5);
|
||||||
|
:if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \
|
||||||
|
message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") });
|
||||||
|
:set CheckHealthCPUUtilizationNotified true;
|
||||||
|
}
|
||||||
|
:if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \
|
||||||
|
message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") });
|
||||||
|
:set CheckHealthCPUUtilizationNotified false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local CheckHealthFreeRAM ($Resource->"free-memory" * 100 / $Resource->"total-memory");
|
||||||
|
:if ($CheckHealthFreeRAM < 20 && $CheckHealthFreeRAMNotified != true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health warning: free RAM"); \
|
||||||
|
message=("The available free RAM on " . $Identity . " is at " . $CheckHealthFreeRAM . "% (" . \
|
||||||
|
($Resource->"free-memory" / 1024 / 1024) . "MiB)!") });
|
||||||
|
:set CheckHealthFreeRAMNotified true;
|
||||||
|
}
|
||||||
|
:if ($CheckHealthFreeRAM > 30 && $CheckHealthFreeRAMNotified = true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health recovery: free RAM"); \
|
||||||
|
message=("The available free RAM on " . $Identity . " increased to " . $CheckHealthFreeRAM . "% (" . \
|
||||||
|
($Resource->"free-memory" / 1024 / 1024) . "MiB).") });
|
||||||
|
:set CheckHealthFreeRAMNotified false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len [ /system/health/find ] ] = 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Your device does not provide any health values.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :typeof $CheckHealthLast ] != "array") do={
|
||||||
|
:set CheckHealthLast ({});
|
||||||
|
}
|
||||||
|
:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={
|
||||||
|
:set CheckHealthTemperatureNotified ({});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:foreach Voltage in=[ /system/health/find where type="V" ] do={
|
||||||
|
:local Name [ /system/health/get $Voltage name ];
|
||||||
|
:local Value [ /system/health/get $Voltage value ];
|
||||||
|
|
||||||
|
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
||||||
|
:local NumCurr [ $TempToNum $Value ];
|
||||||
|
:local NumLast [ $TempToNum ($CheckHealthLast->$Name) ];
|
||||||
|
|
||||||
|
:if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \
|
||||||
|
$NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \
|
||||||
|
$NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \
|
||||||
|
message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \
|
||||||
|
"old value: " . ($CheckHealthLast->$Name) . " V\n" . \
|
||||||
|
"new value: " . $Value . " V") });
|
||||||
|
} else={
|
||||||
|
:if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \
|
||||||
|
message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") });
|
||||||
|
}
|
||||||
|
:if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \
|
||||||
|
message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set ($CheckHealthLast->$Name) $Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={
|
||||||
|
:local Name [ /system/health/get $PSU name ];
|
||||||
|
:local Value [ /system/health/get $PSU value ];
|
||||||
|
|
||||||
|
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
||||||
|
:if ($CheckHealthLast->$Name = "ok" && \
|
||||||
|
$Value != "ok") do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \
|
||||||
|
message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") });
|
||||||
|
}
|
||||||
|
:if ($CheckHealthLast->$Name != "ok" && \
|
||||||
|
$Value = "ok") do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
|
||||||
|
message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set ($CheckHealthLast->$Name) $Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Temperature in=[ /system/health/find where type="C" ] do={
|
||||||
|
:local Name [ /system/health/get $Temperature name ];
|
||||||
|
:local Value [ /system/health/get $Temperature value ];
|
||||||
|
|
||||||
|
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
|
||||||
|
:if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={
|
||||||
|
$LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false;
|
||||||
|
:set ($CheckHealthTemperature->$Name) 50;
|
||||||
|
}
|
||||||
|
:local Validate [ /system/health/get [ find where name=$Name ] value ];
|
||||||
|
:while ($Value != $Validate) do={
|
||||||
|
:set Value $Validate;
|
||||||
|
:set Validate [ /system/health/get [ find where name=$Name ] value ];
|
||||||
|
}
|
||||||
|
:if ($Value > $CheckHealthTemperature->$Name && \
|
||||||
|
$CheckHealthTemperatureNotified->$Name != true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \
|
||||||
|
message=("The " . $Name . " on " . $Identity . " is above threshold: " . \
|
||||||
|
$Value . "\C2\B0" . "C") });
|
||||||
|
:set ($CheckHealthTemperatureNotified->$Name) true;
|
||||||
|
}
|
||||||
|
:if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \
|
||||||
|
$CheckHealthTemperatureNotified->$Name = true) do={
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
|
||||||
|
message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \
|
||||||
|
$Value . "\C2\B0" . "C") });
|
||||||
|
:set ($CheckHealthTemperatureNotified->$Name) false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set ($CheckHealthLast->$Name) $Value;
|
||||||
|
}
|
|
@ -1,82 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: check-lte-firmware-upgrade
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# check for LTE firmware upgrade, send notification
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md
|
|
||||||
|
|
||||||
:local 0 "check-lte-firmware-upgrade";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global SentLteFirmwareUpgradeNotification;
|
|
||||||
|
|
||||||
:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={
|
|
||||||
:global SentLteFirmwareUpgradeNotification ({});
|
|
||||||
}
|
|
||||||
|
|
||||||
:local CheckInterface do={
|
|
||||||
:local Interface $1;
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
:global SentLteFirmwareUpgradeNotification;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptFromTerminal;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
:local IntName [ /interface/lte/get $Interface name ];
|
|
||||||
:local Firmware;
|
|
||||||
:local Info;
|
|
||||||
:do {
|
|
||||||
:set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ];
|
|
||||||
:set Info [ /interface/lte/monitor $Interface once as-value ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \
|
|
||||||
$IntName . ".") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if (($Firmware->"installed") = ($Firmware->"latest")) do={
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = true) do={
|
|
||||||
$LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false;
|
|
||||||
}
|
|
||||||
:return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = true && \
|
|
||||||
[ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={
|
|
||||||
:put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]");
|
|
||||||
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
|
|
||||||
/system/script/run unattended-lte-firmware-upgrade;
|
|
||||||
$LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false;
|
|
||||||
:return true;
|
|
||||||
} else={
|
|
||||||
:put "Canceled...";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \
|
|
||||||
($Firmware->"latest") . ".") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \
|
|
||||||
"LTE interface " . $IntName . ".") false;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \
|
|
||||||
message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \
|
|
||||||
"LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \
|
|
||||||
"Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \
|
|
||||||
"Installed: " . ($Firmware->"installed") . "\n" . \
|
|
||||||
"Available: " . ($Firmware->"latest")); silent=true });
|
|
||||||
:set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest");
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Interface in=[ /interface/lte/find ] do={
|
|
||||||
$CheckInterface $Interface;
|
|
||||||
}
|
|
||||||
|
|
82
check-lte-firmware-upgrade.rsc
Normal file
82
check-lte-firmware-upgrade.rsc
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: check-lte-firmware-upgrade
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# check for LTE firmware upgrade, send notification
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md
|
||||||
|
|
||||||
|
:local 0 "check-lte-firmware-upgrade";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global SentLteFirmwareUpgradeNotification;
|
||||||
|
|
||||||
|
:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={
|
||||||
|
:global SentLteFirmwareUpgradeNotification ({});
|
||||||
|
}
|
||||||
|
|
||||||
|
:local CheckInterface do={
|
||||||
|
:local Interface $1;
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global SentLteFirmwareUpgradeNotification;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptFromTerminal;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
:local IntName [ /interface/lte/get $Interface name ];
|
||||||
|
:local Firmware;
|
||||||
|
:local Info;
|
||||||
|
:do {
|
||||||
|
:set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ];
|
||||||
|
:set Info [ /interface/lte/monitor $Interface once as-value ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \
|
||||||
|
$IntName . ".") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if (($Firmware->"installed") = ($Firmware->"latest")) do={
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = true) do={
|
||||||
|
$LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false;
|
||||||
|
}
|
||||||
|
:return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = true && \
|
||||||
|
[ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={
|
||||||
|
:put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]");
|
||||||
|
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
|
||||||
|
/system/script/run unattended-lte-firmware-upgrade;
|
||||||
|
$LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false;
|
||||||
|
:return true;
|
||||||
|
} else={
|
||||||
|
:put "Canceled...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \
|
||||||
|
($Firmware->"latest") . ".") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \
|
||||||
|
"LTE interface " . $IntName . ".") false;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \
|
||||||
|
message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \
|
||||||
|
"LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \
|
||||||
|
"Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \
|
||||||
|
"Installed: " . ($Firmware->"installed") . "\n" . \
|
||||||
|
"Available: " . ($Firmware->"latest")); silent=true });
|
||||||
|
:set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest");
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Interface in=[ /interface/lte/find ] do={
|
||||||
|
$CheckInterface $Interface;
|
||||||
|
}
|
|
@ -1,147 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: check-routeros-update
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# check for RouterOS update, send notification and/or install
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md
|
|
||||||
|
|
||||||
:local 0 "check-routeros-update";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
:global SafeUpdateAll;
|
|
||||||
:global SafeUpdateNeighbor;
|
|
||||||
:global SafeUpdatePatch;
|
|
||||||
:global SafeUpdateUrl;
|
|
||||||
:global SentRouterosUpdateNotification;
|
|
||||||
|
|
||||||
:global DeviceInfo;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptFromTerminal;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global VersionToNum;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
:local DoUpdate do={
|
|
||||||
:if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={
|
|
||||||
/system/script/run packages-update;
|
|
||||||
} else={
|
|
||||||
/system/package/update/install without-paging;
|
|
||||||
}
|
|
||||||
:error "Waiting for system to reboot.";
|
|
||||||
}
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={
|
|
||||||
:error "A reboot for update is already scheduled.";
|
|
||||||
}
|
|
||||||
|
|
||||||
$LogPrintExit2 debug $0 ("Checking for updates...") false;
|
|
||||||
/system/package/update/check-for-updates without-paging as-value;
|
|
||||||
:local Update [ /system/package/update/get ];
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={
|
|
||||||
$LogPrintExit2 info $0 ("System is already up to date.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local NumInstalled [ $VersionToNum ($Update->"installed-version") ];
|
|
||||||
:local NumLatest [ $VersionToNum ($Update->"latest-version") ];
|
|
||||||
:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree");
|
|
||||||
|
|
||||||
:if ($NumLatest < 117505792) do={
|
|
||||||
$LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($NumInstalled < $NumLatest) do={
|
|
||||||
:if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={
|
|
||||||
$LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \
|
|
||||||
$Update->"latest-version" . "...") false;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
|
||||||
message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \
|
|
||||||
"... Updating on " . $Identity . "..."); link=$Link; silent=true });
|
|
||||||
$DoUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={
|
|
||||||
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
|
||||||
message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \
|
|
||||||
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
|
||||||
$DoUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \
|
|
||||||
version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={
|
|
||||||
$LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
|
||||||
message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \
|
|
||||||
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
|
||||||
$DoUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $SafeUpdateUrl ] > 0) do={
|
|
||||||
:local Result;
|
|
||||||
:do {
|
|
||||||
:set Result [ /tool/fetch check-certificate=yes-without-crl \
|
|
||||||
($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \
|
|
||||||
"&latest=" . $Update->"latest-version") output=user as-value ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false;
|
|
||||||
}
|
|
||||||
:if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={
|
|
||||||
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
|
||||||
message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \
|
|
||||||
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
|
||||||
$DoUpdate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ $ScriptFromTerminal $0 ] = true) do={
|
|
||||||
:put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]");
|
|
||||||
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
|
|
||||||
$DoUpdate;
|
|
||||||
} else={
|
|
||||||
:put "Canceled...";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
|
||||||
$LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \
|
|
||||||
$Update->"latest-version" . ".") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
|
||||||
message=("A new RouterOS version " . ($Update->"latest-version") . \
|
|
||||||
" is available for " . $Identity . ".\n\n" . \
|
|
||||||
[ $DeviceInfo ]); link=$Link; silent=true });
|
|
||||||
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($NumInstalled > $NumLatest) do={
|
|
||||||
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
|
||||||
$LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \
|
|
||||||
$Update->"latest-version" . ".") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \
|
|
||||||
message=("A different RouterOS version " . ($Update->"latest-version") . \
|
|
||||||
" is available for " . $Identity . ", but it is a downgrade.\n\n" . \
|
|
||||||
[ $DeviceInfo ]); link=$Link; silent=true });
|
|
||||||
$LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \
|
|
||||||
" is available for downgrade.") false;
|
|
||||||
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
|
||||||
}
|
|
||||||
|
|
147
check-routeros-update.rsc
Normal file
147
check-routeros-update.rsc
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: check-routeros-update
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# check for RouterOS update, send notification and/or install
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md
|
||||||
|
|
||||||
|
:local 0 "check-routeros-update";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global SafeUpdateAll;
|
||||||
|
:global SafeUpdateNeighbor;
|
||||||
|
:global SafeUpdatePatch;
|
||||||
|
:global SafeUpdateUrl;
|
||||||
|
:global SentRouterosUpdateNotification;
|
||||||
|
|
||||||
|
:global DeviceInfo;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptFromTerminal;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global VersionToNum;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
:local DoUpdate do={
|
||||||
|
:if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={
|
||||||
|
/system/script/run packages-update;
|
||||||
|
} else={
|
||||||
|
/system/package/update/install without-paging;
|
||||||
|
}
|
||||||
|
:error "Waiting for system to reboot.";
|
||||||
|
}
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={
|
||||||
|
:error "A reboot for update is already scheduled.";
|
||||||
|
}
|
||||||
|
|
||||||
|
$LogPrintExit2 debug $0 ("Checking for updates...") false;
|
||||||
|
/system/package/update/check-for-updates without-paging as-value;
|
||||||
|
:local Update [ /system/package/update/get ];
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={
|
||||||
|
$LogPrintExit2 info $0 ("System is already up to date.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local NumInstalled [ $VersionToNum ($Update->"installed-version") ];
|
||||||
|
:local NumLatest [ $VersionToNum ($Update->"latest-version") ];
|
||||||
|
:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree");
|
||||||
|
|
||||||
|
:if ($NumLatest < 117505792) do={
|
||||||
|
$LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($NumInstalled < $NumLatest) do={
|
||||||
|
:if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={
|
||||||
|
$LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \
|
||||||
|
$Update->"latest-version" . "...") false;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
||||||
|
message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \
|
||||||
|
"... Updating on " . $Identity . "..."); link=$Link; silent=true });
|
||||||
|
$DoUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={
|
||||||
|
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
||||||
|
message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \
|
||||||
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
||||||
|
$DoUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \
|
||||||
|
version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={
|
||||||
|
$LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
||||||
|
message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \
|
||||||
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
||||||
|
$DoUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $SafeUpdateUrl ] > 0) do={
|
||||||
|
:local Result;
|
||||||
|
:do {
|
||||||
|
:set Result [ /tool/fetch check-certificate=yes-without-crl \
|
||||||
|
($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \
|
||||||
|
"&latest=" . $Update->"latest-version") output=user as-value ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false;
|
||||||
|
}
|
||||||
|
:if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={
|
||||||
|
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
||||||
|
message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \
|
||||||
|
", updating on " . $Identity . "..."); link=$Link; silent=true });
|
||||||
|
$DoUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ $ScriptFromTerminal $0 ] = true) do={
|
||||||
|
:put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]");
|
||||||
|
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={
|
||||||
|
$DoUpdate;
|
||||||
|
} else={
|
||||||
|
:put "Canceled...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
||||||
|
$LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \
|
||||||
|
$Update->"latest-version" . ".") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \
|
||||||
|
message=("A new RouterOS version " . ($Update->"latest-version") . \
|
||||||
|
" is available for " . $Identity . ".\n\n" . \
|
||||||
|
[ $DeviceInfo ]); link=$Link; silent=true });
|
||||||
|
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($NumInstalled > $NumLatest) do={
|
||||||
|
:if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
|
||||||
|
$LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \
|
||||||
|
$Update->"latest-version" . ".") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \
|
||||||
|
message=("A different RouterOS version " . ($Update->"latest-version") . \
|
||||||
|
" is available for " . $Identity . ", but it is a downgrade.\n\n" . \
|
||||||
|
[ $DeviceInfo ]); link=$Link; silent=true });
|
||||||
|
$LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \
|
||||||
|
" is available for downgrade.") false;
|
||||||
|
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
||||||
|
}
|
|
@ -1,85 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: collect-wireless-mac.capsman
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# collect wireless mac adresses in access list
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md
|
|
||||||
#
|
|
||||||
# provides: lease-script, order=40
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "collect-wireless-mac.capsman";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global GetMacVendor;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
$ScriptLock $0 false 10;
|
|
||||||
|
|
||||||
:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
|
|
||||||
/caps-man/access-list/add comment="--- collected above ---" disabled=yes;
|
|
||||||
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
|
|
||||||
}
|
|
||||||
:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0);
|
|
||||||
|
|
||||||
:foreach Reg in=[ /caps-man/registration-table/find ] do={
|
|
||||||
:local RegVal;
|
|
||||||
:do {
|
|
||||||
:set RegVal [ /caps-man/registration-table/get $Reg ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len ($RegVal->"mac-address") ] > 0) do={
|
|
||||||
:local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
|
|
||||||
:if ([ :len $AccessList ] > 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \
|
|
||||||
[ /caps-man/access-list/get $AccessList comment ]) false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $AccessList ] = 0) do={
|
|
||||||
:local Address "no dhcp lease";
|
|
||||||
:local DnsName "no dhcp lease";
|
|
||||||
:local HostName "no dhcp lease";
|
|
||||||
:local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
|
|
||||||
:if ([ :len $Lease ] > 0) do={
|
|
||||||
:set Address [ /ip/dhcp-server/lease/get $Lease address ];
|
|
||||||
:set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ];
|
|
||||||
:set DnsName "no dns name";
|
|
||||||
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0);
|
|
||||||
:if ([ :len $DnsRec ] > 0) do={
|
|
||||||
:set DnsName [ /ip/dns/static/get $DnsRec name ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]);
|
|
||||||
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ];
|
|
||||||
:local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \
|
|
||||||
"first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface");
|
|
||||||
$LogPrintExit2 info $0 $Message false;
|
|
||||||
/caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \
|
|
||||||
message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \
|
|
||||||
"Controller: " . $Identity . "\n" . \
|
|
||||||
"Interface: " . $RegVal->"interface" . "\n" . \
|
|
||||||
"SSID: " . $RegVal->"ssid" . "\n" . \
|
|
||||||
"MAC: " . $RegVal->"mac-address" . "\n" . \
|
|
||||||
"Vendor: " . $Vendor . "\n" . \
|
|
||||||
"Hostname: " . $HostName . "\n" . \
|
|
||||||
"Address: " . $Address . "\n" . \
|
|
||||||
"DNS name: " . $DnsName . "\n" . \
|
|
||||||
"Date: " . $DateTime) });
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
85
collect-wireless-mac.capsman.rsc
Normal file
85
collect-wireless-mac.capsman.rsc
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: collect-wireless-mac.capsman
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# collect wireless mac adresses in access list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=40
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "collect-wireless-mac.capsman";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global GetMacVendor;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
$ScriptLock $0 false 10;
|
||||||
|
|
||||||
|
:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
|
||||||
|
/caps-man/access-list/add comment="--- collected above ---" disabled=yes;
|
||||||
|
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
|
||||||
|
}
|
||||||
|
:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0);
|
||||||
|
|
||||||
|
:foreach Reg in=[ /caps-man/registration-table/find ] do={
|
||||||
|
:local RegVal;
|
||||||
|
:do {
|
||||||
|
:set RegVal [ /caps-man/registration-table/get $Reg ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($RegVal->"mac-address") ] > 0) do={
|
||||||
|
:local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
|
||||||
|
:if ([ :len $AccessList ] > 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \
|
||||||
|
[ /caps-man/access-list/get $AccessList comment ]) false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $AccessList ] = 0) do={
|
||||||
|
:local Address "no dhcp lease";
|
||||||
|
:local DnsName "no dhcp lease";
|
||||||
|
:local HostName "no dhcp lease";
|
||||||
|
:local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
|
||||||
|
:if ([ :len $Lease ] > 0) do={
|
||||||
|
:set Address [ /ip/dhcp-server/lease/get $Lease address ];
|
||||||
|
:set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ];
|
||||||
|
:set DnsName "no dns name";
|
||||||
|
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0);
|
||||||
|
:if ([ :len $DnsRec ] > 0) do={
|
||||||
|
:set DnsName [ /ip/dns/static/get $DnsRec name ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]);
|
||||||
|
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ];
|
||||||
|
:local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \
|
||||||
|
"first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface");
|
||||||
|
$LogPrintExit2 info $0 $Message false;
|
||||||
|
/caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \
|
||||||
|
message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \
|
||||||
|
"Controller: " . $Identity . "\n" . \
|
||||||
|
"Interface: " . $RegVal->"interface" . "\n" . \
|
||||||
|
"SSID: " . $RegVal->"ssid" . "\n" . \
|
||||||
|
"MAC: " . $RegVal->"mac-address" . "\n" . \
|
||||||
|
"Vendor: " . $Vendor . "\n" . \
|
||||||
|
"Hostname: " . $HostName . "\n" . \
|
||||||
|
"Address: " . $Address . "\n" . \
|
||||||
|
"DNS name: " . $DnsName . "\n" . \
|
||||||
|
"Date: " . $DateTime) });
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,86 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: collect-wireless-mac.local
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# collect wireless mac adresses in access list
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md
|
|
||||||
#
|
|
||||||
# provides: lease-script, order=40
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "collect-wireless-mac.local";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global GetMacVendor;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
$ScriptLock $0 false 10;
|
|
||||||
|
|
||||||
:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
|
|
||||||
/interface/wireless/access-list/add comment="--- collected above ---" disabled=yes;
|
|
||||||
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
|
|
||||||
}
|
|
||||||
:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0);
|
|
||||||
|
|
||||||
:foreach Reg in=[ /interface/wireless/registration-table/find ] do={
|
|
||||||
:local RegVal;
|
|
||||||
:do {
|
|
||||||
:set RegVal [ /interface/wireless/registration-table/get $Reg ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len ($RegVal->"mac-address") ] > 0) do={
|
|
||||||
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
|
|
||||||
:if ([ :len $AccessList ] > 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \
|
|
||||||
[ /interface/wireless/access-list/get $AccessList comment ]) false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $AccessList ] = 0) do={
|
|
||||||
:local Address "no dhcp lease";
|
|
||||||
:local DnsName "no dhcp lease";
|
|
||||||
:local HostName "no dhcp lease";
|
|
||||||
:local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
|
|
||||||
:if ([ :len $Lease ] > 0) do={
|
|
||||||
:set Address [ /ip/dhcp-server/lease/get $Lease address ];
|
|
||||||
:set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ];
|
|
||||||
:set DnsName "no dns name";
|
|
||||||
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0);
|
|
||||||
:if ([ :len $DnsRec ] > 0) do={
|
|
||||||
:set DnsName [ /ip/dns/static/get $DnsRec name ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ];
|
|
||||||
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]);
|
|
||||||
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ];
|
|
||||||
:local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \
|
|
||||||
"first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface");
|
|
||||||
$LogPrintExit2 info $0 $Message false;
|
|
||||||
/interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes;
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \
|
|
||||||
message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \
|
|
||||||
"Controller: " . $Identity . "\n" . \
|
|
||||||
"Interface: " . $RegVal->"interface" . "\n" . \
|
|
||||||
"SSID: " . $RegVal->"ssid" . "\n" . \
|
|
||||||
"MAC: " . $RegVal->"mac-address" . "\n" . \
|
|
||||||
"Vendor: " . $Vendor . "\n" . \
|
|
||||||
"Hostname: " . $HostName . "\n" . \
|
|
||||||
"Address: " . $Address . "\n" . \
|
|
||||||
"DNS name: " . $DnsName . "\n" . \
|
|
||||||
"Date: " . $DateTime) });
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
86
collect-wireless-mac.local.rsc
Normal file
86
collect-wireless-mac.local.rsc
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: collect-wireless-mac.local
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# collect wireless mac adresses in access list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=40
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "collect-wireless-mac.local";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global GetMacVendor;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
$ScriptLock $0 false 10;
|
||||||
|
|
||||||
|
:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
|
||||||
|
/interface/wireless/access-list/add comment="--- collected above ---" disabled=yes;
|
||||||
|
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
|
||||||
|
}
|
||||||
|
:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0);
|
||||||
|
|
||||||
|
:foreach Reg in=[ /interface/wireless/registration-table/find ] do={
|
||||||
|
:local RegVal;
|
||||||
|
:do {
|
||||||
|
:set RegVal [ /interface/wireless/registration-table/get $Reg ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($RegVal->"mac-address") ] > 0) do={
|
||||||
|
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
|
||||||
|
:if ([ :len $AccessList ] > 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \
|
||||||
|
[ /interface/wireless/access-list/get $AccessList comment ]) false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $AccessList ] = 0) do={
|
||||||
|
:local Address "no dhcp lease";
|
||||||
|
:local DnsName "no dhcp lease";
|
||||||
|
:local HostName "no dhcp lease";
|
||||||
|
:local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
|
||||||
|
:if ([ :len $Lease ] > 0) do={
|
||||||
|
:set Address [ /ip/dhcp-server/lease/get $Lease address ];
|
||||||
|
:set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ];
|
||||||
|
:set DnsName "no dns name";
|
||||||
|
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0);
|
||||||
|
:if ([ :len $DnsRec ] > 0) do={
|
||||||
|
:set DnsName [ /ip/dns/static/get $DnsRec name ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ];
|
||||||
|
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]);
|
||||||
|
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ];
|
||||||
|
:local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \
|
||||||
|
"first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface");
|
||||||
|
$LogPrintExit2 info $0 $Message false;
|
||||||
|
/interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes;
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \
|
||||||
|
message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \
|
||||||
|
"Controller: " . $Identity . "\n" . \
|
||||||
|
"Interface: " . $RegVal->"interface" . "\n" . \
|
||||||
|
"SSID: " . $RegVal->"ssid" . "\n" . \
|
||||||
|
"MAC: " . $RegVal->"mac-address" . "\n" . \
|
||||||
|
"Vendor: " . $Vendor . "\n" . \
|
||||||
|
"Hostname: " . $HostName . "\n" . \
|
||||||
|
"Address: " . $Address . "\n" . \
|
||||||
|
"DNS name: " . $DnsName . "\n" . \
|
||||||
|
"Date: " . $DateTime) });
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,96 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: daily-psk.capsman
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# Michael Gisbers <michael@gisbers.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# update daily PSK (pre shared key)
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "daily-psk.capsman";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
|
||||||
:global DailyPskQrCodeUrl;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global UrlEncode;
|
|
||||||
:global WaitForFile;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
# return pseudo-random string for PSK
|
|
||||||
:local GeneratePSK do={
|
|
||||||
:local Date [ :tostr $1 ];
|
|
||||||
|
|
||||||
:global DailyPskSecrets;
|
|
||||||
|
|
||||||
:local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
|
|
||||||
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
|
|
||||||
|
|
||||||
:local Month [ :pick $Date 0 3 ];
|
|
||||||
:local Day [ :tonum [ :pick $Date 4 6 ] ];
|
|
||||||
:local Year [ :pick $Date 7 11 ];
|
|
||||||
|
|
||||||
:for MIndex from=0 to=[ :len $Months ] do={
|
|
||||||
:if ($Months->$MIndex = $Month) do={
|
|
||||||
:set Month ($MIndex + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local A ((14 - $Month) / 12);
|
|
||||||
:local B ($Year - $A);
|
|
||||||
:local C ($Month + 12 * $A - 2);
|
|
||||||
:local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12));
|
|
||||||
:set WeekDay ($WeekDay - (($WeekDay / 7) * 7));
|
|
||||||
|
|
||||||
:return (($DailyPskSecrets->0->($Day - 1)) . \
|
|
||||||
($DailyPskSecrets->1->($Month - 1)) . \
|
|
||||||
($DailyPskSecrets->2->$WeekDay));
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Seen ({});
|
|
||||||
:local Date [ /system/clock/get date ];
|
|
||||||
:local NewPsk [ $GeneratePSK $Date ];
|
|
||||||
|
|
||||||
:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={
|
|
||||||
:local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ];
|
|
||||||
:local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0);
|
|
||||||
:local Ssid [ /caps-man/configuration/get $Configuration ssid ];
|
|
||||||
:local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ];
|
|
||||||
:local Skip 0;
|
|
||||||
|
|
||||||
:if ($NewPsk != $OldPsk) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false;
|
|
||||||
/caps-man/access-list/set $AccList private-passphrase=$NewPsk;
|
|
||||||
|
|
||||||
:if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={
|
|
||||||
:foreach SeenSsid in=$Seen do={
|
|
||||||
:if ($SeenSsid = $Ssid) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
|
|
||||||
:set Skip 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($Skip = 0) do={
|
|
||||||
:set Seen ($Seen, $Ssid);
|
|
||||||
:local Link ($DailyPskQrCodeUrl . \
|
|
||||||
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
|
|
||||||
message=("This is the daily PSK on " . $Identity . ":\n\n" . \
|
|
||||||
"SSID: " . $Ssid . "\n" . \
|
|
||||||
"PSK: " . $NewPsk . "\n" . \
|
|
||||||
"Date: " . $Date . "\n\n" . \
|
|
||||||
"A client device specific rule must not exist!"); link=$Link });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
96
daily-psk.capsman.rsc
Normal file
96
daily-psk.capsman.rsc
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: daily-psk.capsman
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# Michael Gisbers <michael@gisbers.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# update daily PSK (pre shared key)
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "daily-psk.capsman";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global DailyPskMatchComment;
|
||||||
|
:global DailyPskQrCodeUrl;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global UrlEncode;
|
||||||
|
:global WaitForFile;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
# return pseudo-random string for PSK
|
||||||
|
:local GeneratePSK do={
|
||||||
|
:local Date [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global DailyPskSecrets;
|
||||||
|
|
||||||
|
:local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
|
||||||
|
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
|
||||||
|
|
||||||
|
:local Month [ :pick $Date 0 3 ];
|
||||||
|
:local Day [ :tonum [ :pick $Date 4 6 ] ];
|
||||||
|
:local Year [ :pick $Date 7 11 ];
|
||||||
|
|
||||||
|
:for MIndex from=0 to=[ :len $Months ] do={
|
||||||
|
:if ($Months->$MIndex = $Month) do={
|
||||||
|
:set Month ($MIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:local A ((14 - $Month) / 12);
|
||||||
|
:local B ($Year - $A);
|
||||||
|
:local C ($Month + 12 * $A - 2);
|
||||||
|
:local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12));
|
||||||
|
:set WeekDay ($WeekDay - (($WeekDay / 7) * 7));
|
||||||
|
|
||||||
|
:return (($DailyPskSecrets->0->($Day - 1)) . \
|
||||||
|
($DailyPskSecrets->1->($Month - 1)) . \
|
||||||
|
($DailyPskSecrets->2->$WeekDay));
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Seen ({});
|
||||||
|
:local Date [ /system/clock/get date ];
|
||||||
|
:local NewPsk [ $GeneratePSK $Date ];
|
||||||
|
|
||||||
|
:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={
|
||||||
|
:local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ];
|
||||||
|
:local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0);
|
||||||
|
:local Ssid [ /caps-man/configuration/get $Configuration ssid ];
|
||||||
|
:local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ];
|
||||||
|
:local Skip 0;
|
||||||
|
|
||||||
|
:if ($NewPsk != $OldPsk) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false;
|
||||||
|
/caps-man/access-list/set $AccList private-passphrase=$NewPsk;
|
||||||
|
|
||||||
|
:if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={
|
||||||
|
:foreach SeenSsid in=$Seen do={
|
||||||
|
:if ($SeenSsid = $Ssid) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
|
||||||
|
:set Skip 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($Skip = 0) do={
|
||||||
|
:set Seen ($Seen, $Ssid);
|
||||||
|
:local Link ($DailyPskQrCodeUrl . \
|
||||||
|
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
|
||||||
|
message=("This is the daily PSK on " . $Identity . ":\n\n" . \
|
||||||
|
"SSID: " . $Ssid . "\n" . \
|
||||||
|
"PSK: " . $NewPsk . "\n" . \
|
||||||
|
"Date: " . $Date . "\n\n" . \
|
||||||
|
"A client device specific rule must not exist!"); link=$Link });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,95 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: daily-psk.local
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# Michael Gisbers <michael@gisbers.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# update daily PSK (pre shared key)
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "daily-psk.local";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
|
||||||
:global DailyPskQrCodeUrl;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global UrlEncode;
|
|
||||||
:global WaitForFile;
|
|
||||||
:global WaitFullyConnected;
|
|
||||||
|
|
||||||
$WaitFullyConnected;
|
|
||||||
|
|
||||||
# return pseudo-random string for PSK
|
|
||||||
:local GeneratePSK do={
|
|
||||||
:local Date [ :tostr $1 ];
|
|
||||||
|
|
||||||
:global DailyPskSecrets;
|
|
||||||
|
|
||||||
:local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
|
|
||||||
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
|
|
||||||
|
|
||||||
:local Month [ :pick $Date 0 3 ];
|
|
||||||
:local Day [ :tonum [ :pick $Date 4 6 ] ];
|
|
||||||
:local Year [ :pick $Date 7 11 ];
|
|
||||||
|
|
||||||
:for MIndex from=0 to=[ :len $Months ] do={
|
|
||||||
:if ($Months->$MIndex = $Month) do={
|
|
||||||
:set Month ($MIndex + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local A ((14 - $Month) / 12);
|
|
||||||
:local B ($Year - $A);
|
|
||||||
:local C ($Month + 12 * $A - 2);
|
|
||||||
:local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12));
|
|
||||||
:set WeekDay ($WeekDay - (($WeekDay / 7) * 7));
|
|
||||||
|
|
||||||
:return (($DailyPskSecrets->0->($Day - 1)) . \
|
|
||||||
($DailyPskSecrets->1->($Month - 1)) . \
|
|
||||||
($DailyPskSecrets->2->$WeekDay));
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Seen ({});
|
|
||||||
:local Date [ /system/clock/get date ];
|
|
||||||
:local NewPsk [ $GeneratePSK $Date ];
|
|
||||||
|
|
||||||
:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={
|
|
||||||
:local IntName [ /interface/wireless/access-list/get $AccList interface ];
|
|
||||||
:local Ssid [ /interface/wireless/get $IntName ssid ];
|
|
||||||
:local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ];
|
|
||||||
:local Skip 0;
|
|
||||||
|
|
||||||
:if ($NewPsk != $OldPsk) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false;
|
|
||||||
/interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk;
|
|
||||||
|
|
||||||
:if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={
|
|
||||||
:foreach SeenSsid in=$Seen do={
|
|
||||||
:if ($SeenSsid = $Ssid) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
|
|
||||||
:set Skip 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($Skip = 0) do={
|
|
||||||
:set Seen ($Seen, $Ssid);
|
|
||||||
:local Link ($DailyPskQrCodeUrl . \
|
|
||||||
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
|
|
||||||
message=("This is the daily PSK on " . $Identity . ":\n\n" . \
|
|
||||||
"SSID: " . $Ssid . "\n" . \
|
|
||||||
"PSK: " . $NewPsk . "\n" . \
|
|
||||||
"Date: " . $Date . "\n\n" . \
|
|
||||||
"A client device specific rule must not exist!"); link=$Link });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
95
daily-psk.local.rsc
Normal file
95
daily-psk.local.rsc
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: daily-psk.local
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# Michael Gisbers <michael@gisbers.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# update daily PSK (pre shared key)
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "daily-psk.local";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global DailyPskMatchComment;
|
||||||
|
:global DailyPskQrCodeUrl;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global UrlEncode;
|
||||||
|
:global WaitForFile;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
# return pseudo-random string for PSK
|
||||||
|
:local GeneratePSK do={
|
||||||
|
:local Date [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global DailyPskSecrets;
|
||||||
|
|
||||||
|
:local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun";
|
||||||
|
"jul"; "aug"; "sep"; "oct"; "nov"; "dec" };
|
||||||
|
|
||||||
|
:local Month [ :pick $Date 0 3 ];
|
||||||
|
:local Day [ :tonum [ :pick $Date 4 6 ] ];
|
||||||
|
:local Year [ :pick $Date 7 11 ];
|
||||||
|
|
||||||
|
:for MIndex from=0 to=[ :len $Months ] do={
|
||||||
|
:if ($Months->$MIndex = $Month) do={
|
||||||
|
:set Month ($MIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:local A ((14 - $Month) / 12);
|
||||||
|
:local B ($Year - $A);
|
||||||
|
:local C ($Month + 12 * $A - 2);
|
||||||
|
:local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12));
|
||||||
|
:set WeekDay ($WeekDay - (($WeekDay / 7) * 7));
|
||||||
|
|
||||||
|
:return (($DailyPskSecrets->0->($Day - 1)) . \
|
||||||
|
($DailyPskSecrets->1->($Month - 1)) . \
|
||||||
|
($DailyPskSecrets->2->$WeekDay));
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Seen ({});
|
||||||
|
:local Date [ /system/clock/get date ];
|
||||||
|
:local NewPsk [ $GeneratePSK $Date ];
|
||||||
|
|
||||||
|
:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={
|
||||||
|
:local IntName [ /interface/wireless/access-list/get $AccList interface ];
|
||||||
|
:local Ssid [ /interface/wireless/get $IntName ssid ];
|
||||||
|
:local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ];
|
||||||
|
:local Skip 0;
|
||||||
|
|
||||||
|
:if ($NewPsk != $OldPsk) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false;
|
||||||
|
/interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk;
|
||||||
|
|
||||||
|
:if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={
|
||||||
|
:foreach SeenSsid in=$Seen do={
|
||||||
|
:if ($SeenSsid = $Ssid) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
|
||||||
|
:set Skip 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($Skip = 0) do={
|
||||||
|
:set Seen ($Seen, $Ssid);
|
||||||
|
:local Link ($DailyPskQrCodeUrl . \
|
||||||
|
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
|
||||||
|
message=("This is the daily PSK on " . $Identity . ":\n\n" . \
|
||||||
|
"SSID: " . $Ssid . "\n" . \
|
||||||
|
"PSK: " . $NewPsk . "\n" . \
|
||||||
|
"Date: " . $Date . "\n\n" . \
|
||||||
|
"A client device specific rule must not exist!"); link=$Link });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: dhcp-lease-comment.capsman
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: lease-script, order=60
|
# dummy for migration
|
||||||
#
|
|
||||||
# update dhcp-server lease comment with infos from access-list
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "dhcp-lease-comment.capsman";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
|
|
||||||
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
|
||||||
:local NewComment;
|
|
||||||
:local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0);
|
|
||||||
:if ([ :len $AccessList ] > 0) do={
|
|
||||||
:set NewComment [ /caps-man/access-list/get $AccessList comment ];
|
|
||||||
}
|
|
||||||
:if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false;
|
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
30
dhcp-lease-comment.capsman.rsc
Normal file
30
dhcp-lease-comment.capsman.rsc
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: dhcp-lease-comment.capsman
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=60
|
||||||
|
#
|
||||||
|
# update dhcp-server lease comment with infos from access-list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "dhcp-lease-comment.capsman";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
|
||||||
|
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
||||||
|
:local NewComment;
|
||||||
|
:local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0);
|
||||||
|
:if ([ :len $AccessList ] > 0) do={
|
||||||
|
:set NewComment [ /caps-man/access-list/get $AccessList comment ];
|
||||||
|
}
|
||||||
|
:if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false;
|
||||||
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: dhcp-lease-comment.local
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: lease-script, order=60
|
# dummy for migration
|
||||||
#
|
|
||||||
# update dhcp-server lease comment with infos from access-list
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md
|
|
||||||
#
|
|
||||||
# !! Do not edit this file, it is generated from template!
|
|
||||||
|
|
||||||
:local 0 "dhcp-lease-comment.local";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
|
|
||||||
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
|
||||||
:local NewComment;
|
|
||||||
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0);
|
|
||||||
:if ([ :len $AccessList ] > 0) do={
|
|
||||||
:set NewComment [ /interface/wireless/access-list/get $AccessList comment ];
|
|
||||||
}
|
|
||||||
:if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false;
|
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
30
dhcp-lease-comment.local.rsc
Normal file
30
dhcp-lease-comment.local.rsc
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: dhcp-lease-comment.local
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=60
|
||||||
|
#
|
||||||
|
# update dhcp-server lease comment with infos from access-list
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md
|
||||||
|
#
|
||||||
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
|
:local 0 "dhcp-lease-comment.local";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
|
||||||
|
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
||||||
|
:local NewComment;
|
||||||
|
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0);
|
||||||
|
:if ([ :len $AccessList ] > 0) do={
|
||||||
|
:set NewComment [ /interface/wireless/access-list/get $AccessList comment ];
|
||||||
|
}
|
||||||
|
:if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false;
|
||||||
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
|
}
|
||||||
|
}
|
96
dhcp-to-dns
96
dhcp-to-dns
|
@ -1,97 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: dhcp-to-dns
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: lease-script, order=20
|
# dummy for migration
|
||||||
#
|
|
||||||
# check DHCP leases and add/remove/update DNS entries
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md
|
|
||||||
|
|
||||||
:local 0 "dhcp-to-dns";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Domain;
|
|
||||||
:global HostNameInZone;
|
|
||||||
:global Identity;
|
|
||||||
:global PrefixInZone;
|
|
||||||
:global ServerNameInZone;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
|
|
||||||
$ScriptLock $0 false 10;
|
|
||||||
|
|
||||||
:local Zone \
|
|
||||||
([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \
|
|
||||||
[ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain);
|
|
||||||
:local Ttl 5m;
|
|
||||||
:local CommentPrefix ("managed by " . $0 . " for ");
|
|
||||||
:local CommentString ("--- " . $0 . " above ---");
|
|
||||||
|
|
||||||
:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={
|
|
||||||
/ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes;
|
|
||||||
$LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false;
|
|
||||||
}
|
|
||||||
:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0);
|
|
||||||
|
|
||||||
:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={
|
|
||||||
:local DnsRecordVal [ /ip/dns/static/get $DnsRecord ];
|
|
||||||
:local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ];
|
|
||||||
:if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false;
|
|
||||||
} else={
|
|
||||||
:local Found false;
|
|
||||||
$LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false;
|
|
||||||
/ip/dns/static/remove $DnsRecord;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={
|
|
||||||
:local LeaseVal;
|
|
||||||
:do {
|
|
||||||
:set LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len ($LeaseVal->"address") ] > 0) do={
|
|
||||||
:local Comment ($CommentPrefix . $LeaseVal->"mac-address");
|
|
||||||
:local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \
|
|
||||||
[ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \
|
|
||||||
[ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ];
|
|
||||||
|
|
||||||
:local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone);
|
|
||||||
:local DnsRecord [ /ip/dns/static/find where name=$Fqdn ];
|
|
||||||
:if ([ :len $DnsRecord ] > 0) do={
|
|
||||||
:local DnsIp [ /ip/dns/static/get $DnsRecord address ];
|
|
||||||
|
|
||||||
:local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ];
|
|
||||||
:if ([ :len $DupMacLeases ] > 1) do={
|
|
||||||
:set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ];
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len ($LeaseVal->"host-name") ] > 0) do={
|
|
||||||
:local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ];
|
|
||||||
:if ([ :len $HostNameLeases ] > 1) do={
|
|
||||||
:set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($DnsIp = $LeaseVal->"address") do={
|
|
||||||
$LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false;
|
|
||||||
/ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false;
|
|
||||||
/ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("No address available... Ignoring.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
97
dhcp-to-dns.rsc
Normal file
97
dhcp-to-dns.rsc
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: dhcp-to-dns
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=20
|
||||||
|
#
|
||||||
|
# check DHCP leases and add/remove/update DNS entries
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md
|
||||||
|
|
||||||
|
:local 0 "dhcp-to-dns";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Domain;
|
||||||
|
:global HostNameInZone;
|
||||||
|
:global Identity;
|
||||||
|
:global PrefixInZone;
|
||||||
|
:global ServerNameInZone;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
|
||||||
|
$ScriptLock $0 false 10;
|
||||||
|
|
||||||
|
:local Zone \
|
||||||
|
([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \
|
||||||
|
[ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain);
|
||||||
|
:local Ttl 5m;
|
||||||
|
:local CommentPrefix ("managed by " . $0 . " for ");
|
||||||
|
:local CommentString ("--- " . $0 . " above ---");
|
||||||
|
|
||||||
|
:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={
|
||||||
|
/ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes;
|
||||||
|
$LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false;
|
||||||
|
}
|
||||||
|
:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0);
|
||||||
|
|
||||||
|
:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={
|
||||||
|
:local DnsRecordVal [ /ip/dns/static/get $DnsRecord ];
|
||||||
|
:local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ];
|
||||||
|
:if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false;
|
||||||
|
} else={
|
||||||
|
:local Found false;
|
||||||
|
$LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false;
|
||||||
|
/ip/dns/static/remove $DnsRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={
|
||||||
|
:local LeaseVal;
|
||||||
|
:do {
|
||||||
|
:set LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($LeaseVal->"address") ] > 0) do={
|
||||||
|
:local Comment ($CommentPrefix . $LeaseVal->"mac-address");
|
||||||
|
:local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \
|
||||||
|
[ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \
|
||||||
|
[ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ];
|
||||||
|
|
||||||
|
:local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone);
|
||||||
|
:local DnsRecord [ /ip/dns/static/find where name=$Fqdn ];
|
||||||
|
:if ([ :len $DnsRecord ] > 0) do={
|
||||||
|
:local DnsIp [ /ip/dns/static/get $DnsRecord address ];
|
||||||
|
|
||||||
|
:local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ];
|
||||||
|
:if ([ :len $DupMacLeases ] > 1) do={
|
||||||
|
:set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ];
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($LeaseVal->"host-name") ] > 0) do={
|
||||||
|
:local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ];
|
||||||
|
:if ([ :len $HostNameLeases ] > 1) do={
|
||||||
|
:set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($DnsIp = $LeaseVal->"address") do={
|
||||||
|
$LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false;
|
||||||
|
/ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false;
|
||||||
|
/ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("No address available... Ignoring.") false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,8 +28,8 @@ The optional configuration goes to `global-config-overlay`.
|
||||||
* `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter
|
* `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter
|
||||||
|
|
||||||
If the parameter passed to the function is not a complete URL (starting
|
If the parameter passed to the function is not a complete URL (starting
|
||||||
with protocol `ftp://`, `http://`, `https://` or `sftp://`) the values are
|
with protocol `ftp://`, `http://`, `https://` or `sftp://`) the base-url is
|
||||||
prepended and appended.
|
prepended, and file extension `.rsc` and url-suffix are appended.
|
||||||
|
|
||||||
Usage and invocation
|
Usage and invocation
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -1,42 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: firmware-upgrade-reboot
|
|
||||||
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# install firmware upgrade, and reboot
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md
|
|
||||||
|
|
||||||
:local 0 "firmware-upgrade-reboot";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global VersionToNum;
|
|
||||||
|
|
||||||
:local RouterBoard [ /system/routerboard/get ];
|
|
||||||
:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={
|
|
||||||
$LogPrintExit2 info $0 ("Current and upgrade firmware match with version " . \
|
|
||||||
$RouterBoard->"current-firmware" . ".") true;
|
|
||||||
}
|
|
||||||
:if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={
|
|
||||||
$LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={
|
|
||||||
$LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \
|
|
||||||
" is available, upgrading.") false;
|
|
||||||
/system/routerboard/upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \
|
|
||||||
message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={
|
|
||||||
:delay 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Uptime [ /system/resource/get uptime ];
|
|
||||||
:if ($Uptime < 1m) do={
|
|
||||||
:delay $Uptime;
|
|
||||||
}
|
|
||||||
|
|
||||||
$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false;
|
|
||||||
/system/reboot;
|
|
||||||
|
|
42
firmware-upgrade-reboot.rsc
Normal file
42
firmware-upgrade-reboot.rsc
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: firmware-upgrade-reboot
|
||||||
|
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# install firmware upgrade, and reboot
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md
|
||||||
|
|
||||||
|
:local 0 "firmware-upgrade-reboot";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global VersionToNum;
|
||||||
|
|
||||||
|
:local RouterBoard [ /system/routerboard/get ];
|
||||||
|
:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={
|
||||||
|
$LogPrintExit2 info $0 ("Current and upgrade firmware match with version " . \
|
||||||
|
$RouterBoard->"current-firmware" . ".") true;
|
||||||
|
}
|
||||||
|
:if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={
|
||||||
|
$LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={
|
||||||
|
$LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \
|
||||||
|
" is available, upgrading.") false;
|
||||||
|
/system/routerboard/upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \
|
||||||
|
message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={
|
||||||
|
:delay 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Uptime [ /system/resource/get uptime ];
|
||||||
|
:if ($Uptime < 1m) do={
|
||||||
|
:delay $Uptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false;
|
||||||
|
/system/reboot;
|
219
global-config
219
global-config
|
@ -1,220 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: global-config
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# global configuration
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/
|
|
||||||
|
|
||||||
# Set this to 'true' to disable news and change notifications.
|
|
||||||
:global NoNewsAndChangesNotification false;
|
|
||||||
|
|
||||||
# Add extra text (or emojis) in notification tags.
|
|
||||||
:global IdentityExtra "";
|
|
||||||
|
|
||||||
# This is used for DNS and backup file.
|
|
||||||
:global Domain "example.com";
|
|
||||||
:global HostNameInZone true;
|
|
||||||
:global PrefixInZone true;
|
|
||||||
:global ServerNameInZone false;
|
|
||||||
|
|
||||||
# You can send e-mail notifications. Configure the system's mail settings
|
|
||||||
# (/tool/e-mail), then install the module:
|
|
||||||
# $ScriptInstallUpdate mod/notification-email
|
|
||||||
# The to-address needs to be filled; cc-address can be empty, one address
|
|
||||||
# or a comma separated list of addresses.
|
|
||||||
:global EmailGeneralTo "";
|
|
||||||
:global EmailGeneralCc "";
|
|
||||||
#:global EmailGeneralTo "mail@example.com";
|
|
||||||
#:global EmailGeneralCc "another@example.com,third@example.com";
|
|
||||||
|
|
||||||
# You can send Telegram notifications. Register a bot
|
|
||||||
# and add the token and chat ids here, then install the module:
|
|
||||||
# $ScriptInstallUpdate mod/notification-telegram
|
|
||||||
:global TelegramTokenId "";
|
|
||||||
:global TelegramChatId "";
|
|
||||||
#:global TelegramTokenId "123456:ABCDEF-GHI";
|
|
||||||
#:global TelegramChatId "12345678";
|
|
||||||
# Using telegram-chat you have to define trusted chat ids (not group ids!)
|
|
||||||
# or user names. Groups allow to chat with devices simultaneously.
|
|
||||||
#:global TelegramChatIdsTrusted {
|
|
||||||
# "12345678";
|
|
||||||
# "example_user";
|
|
||||||
#};
|
|
||||||
:global TelegramChatGroups "(all)";
|
|
||||||
#:global TelegramChatGroups "(all|home|office)";
|
|
||||||
# This is whether or not to send Telegram messages with fixed-width font.
|
|
||||||
:global TelegramFixedWidthFont true;
|
|
||||||
|
|
||||||
# You can send Matrix notifications. Configure these settings and
|
|
||||||
# install the module:
|
|
||||||
# $ScriptInstallUpdate mod/notification-matrix
|
|
||||||
:global MatrixHomeServer "";
|
|
||||||
:global MatrixAccessToken "";
|
|
||||||
:global MatrixRoom "";
|
|
||||||
#:global MatrixHomeServer "matrix.org";
|
|
||||||
#:global MatrixAccessToken "123456ABCDEFGHI...";
|
|
||||||
#:global MatrixRoom "!example:matrix.org";
|
|
||||||
|
|
||||||
# It is possible to override e-mail, Telegram and Matrix setting for every
|
|
||||||
# script. This is done in arrays, where 'Override' is appended to the
|
|
||||||
# variable name, like this:
|
|
||||||
#:global EmailGeneralToOverride {
|
|
||||||
# "check-certificates"="override@example.com";
|
|
||||||
# "backup-email"="backup@example.com";
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Toggle this to disable symbols in notifications.
|
|
||||||
:global NotificationsWithSymbols true;
|
|
||||||
# Toggle this to disable color output in terminal/cli.
|
|
||||||
:global TerminalColorOutput true;
|
|
||||||
|
|
||||||
# This defines what backups to generate and what password to use.
|
|
||||||
:global BackupSendBinary false;
|
|
||||||
:global BackupSendExport true;
|
|
||||||
:global BackupSendGlobalConfig true;
|
|
||||||
:global BackupPassword "v3ry-s3cr3t";
|
|
||||||
:global BackupRandomDelay 0;
|
|
||||||
# These credentials are used to upload backup and config export files.
|
|
||||||
# SFTP authentication is tricky, you may have to limit authentication
|
|
||||||
# methods for your SSH server.
|
|
||||||
:global BackupUploadUrl "sftp://example.com/backup/";
|
|
||||||
:global BackupUploadUser "mikrotik";
|
|
||||||
:global BackupUploadPass "v3ry-s3cr3t";
|
|
||||||
|
|
||||||
# This defines what log messages to filter or include by topic or message
|
|
||||||
# text. Regular expressions are supported. Do *NOT* set an empty string,
|
|
||||||
# that will filter or include everything!
|
|
||||||
# These are filters, so excluding messages from forwarding.
|
|
||||||
:global LogForwardFilter "(debug|info)";
|
|
||||||
:global LogForwardFilterMessage [];
|
|
||||||
#:global LogForwardFilterMessage "message text";
|
|
||||||
#:global LogForwardFilterMessage "(message text|another text|...)";
|
|
||||||
# ... and another setting with reverse logic. This includes messages even
|
|
||||||
# if filtered above.
|
|
||||||
:global LogForwardInclude [];
|
|
||||||
:global LogForwardIncludeMessage [];
|
|
||||||
#:global LogForwardInclude "account";
|
|
||||||
#:global LogForwardIncludeMessage "message text";
|
|
||||||
|
|
||||||
# Specify an address to enable auto update to version assumed safe.
|
|
||||||
# The configured channel (bugfix, current, release-candidate) is appended.
|
|
||||||
:global SafeUpdateUrl "";
|
|
||||||
#:global SafeUpdateUrl "https://example.com/ros/safe-update/";
|
|
||||||
# Allow to install patch updates automatically.
|
|
||||||
:global SafeUpdatePatch false;
|
|
||||||
# Allow to install updates automatically if seen in neighbor list.
|
|
||||||
:global SafeUpdateNeighbor false;
|
|
||||||
# Install *ALL* updates automatically!
|
|
||||||
# Set to all upper-case "Yes, please!" to enable.
|
|
||||||
:global SafeUpdateAll "no";
|
|
||||||
|
|
||||||
# These thresholds control when to send health notification
|
|
||||||
# on temperature and voltage.
|
|
||||||
:global CheckHealthTemperature {
|
|
||||||
temperature=50;
|
|
||||||
cpu-temperature=70;
|
|
||||||
board-temperature1=50;
|
|
||||||
board-temperature2=50;
|
|
||||||
}
|
|
||||||
# This is deviation on recovery threshold against notification flooding.
|
|
||||||
:global CheckHealthTemperatureDeviation 3;
|
|
||||||
:global CheckHealthVoltageLow 115;
|
|
||||||
:global CheckHealthVoltagePercent 10;
|
|
||||||
|
|
||||||
# Access-list entries matching this comment are updated
|
|
||||||
# with daily pseudo-random PSK.
|
|
||||||
:global DailyPskMatchComment "Daily PSK";
|
|
||||||
:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi";
|
|
||||||
:global DailyPskSecrets {
|
|
||||||
{ "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold";
|
|
||||||
"Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite";
|
|
||||||
"Evasive"; "Faded"; "Flat"; "Future"; "Grandiose";
|
|
||||||
"Hanging"; "Humorous"; "Interesting"; "Magenta";
|
|
||||||
"Magnificent"; "Numerous"; "Optimal"; "Pathetic";
|
|
||||||
"Possessive"; "Remarkable"; "Rightful"; "Ruthless";
|
|
||||||
"Stale"; "Unusual"; "Useless"; "Various" };
|
|
||||||
{ "Adhesive"; "Amusing"; "Astonishing"; "Frantic";
|
|
||||||
"Kindhearted"; "Limping"; "Roasted"; "Robust";
|
|
||||||
"Staking"; "Thundering"; "Ultra"; "Unreal" };
|
|
||||||
{ "Belief"; "Button"; "Curtain"; "Edge"; "Jewel";
|
|
||||||
"String"; "Whistle" }
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run different commands with multiple mode-button presses.
|
|
||||||
:global ModeButton {
|
|
||||||
1="/system/script/run leds-toggle-mode;";
|
|
||||||
2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");";
|
|
||||||
3="/system/shutdown;";
|
|
||||||
4="/system/reboot;";
|
|
||||||
5=":global BridgePortVlan; \$BridgePortVlan alt;";
|
|
||||||
# add more here...
|
|
||||||
};
|
|
||||||
# This led gives visual feedback if type is 'on' or 'off'.
|
|
||||||
:global ModeButtonLED "user-led";
|
|
||||||
|
|
||||||
# Run commands on SMS action.
|
|
||||||
:global SmsAction {
|
|
||||||
bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;";
|
|
||||||
reboot="/system/reboot;";
|
|
||||||
shutdown="/system/shutdown;";
|
|
||||||
# add more here...
|
|
||||||
};
|
|
||||||
|
|
||||||
# Run commands by hooking into SMS forward.
|
|
||||||
:global SmsForwardHooks {
|
|
||||||
{ match="magic string";
|
|
||||||
allowed-number="12345678";
|
|
||||||
command="/system/script/run ..." };
|
|
||||||
# add more here...
|
|
||||||
};
|
|
||||||
|
|
||||||
# This is the address used to send gps data to.
|
|
||||||
:global GpsTrackUrl "https://example.com/index.php";
|
|
||||||
|
|
||||||
# Enable this to fetch scripts from given url.
|
|
||||||
:global ScriptUpdatesFetch true;
|
|
||||||
:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/";
|
|
||||||
# alternative urls - main: stable code - next: currently in development
|
|
||||||
#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/";
|
|
||||||
#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/";
|
|
||||||
#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/";
|
|
||||||
#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/";
|
|
||||||
:global ScriptUpdatesUrlSuffix "";
|
|
||||||
# use next branch with default url (git.eworm.de)
|
|
||||||
#:global ScriptUpdatesUrlSuffix "\?h=next";
|
|
||||||
|
|
||||||
# Use this for defaults with $ScriptRunOnce
|
|
||||||
# Install module with:
|
|
||||||
# $ScriptInstallUpdate mod/scriptrunonce
|
|
||||||
:global ScriptRunOnceBaseUrl "";
|
|
||||||
:global ScriptRunOnceUrlSuffix "";
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/#donate
|
|
||||||
# Enable this to silence donation hint.
|
|
||||||
:global IDonate false;
|
|
||||||
|
|
||||||
# Use this for certificate auto-renew
|
|
||||||
:global CertRenewUrl "";
|
|
||||||
#:global CertRenewUrl "https://example.com/certificates/";
|
|
||||||
:global CertRenewTime 3w;
|
|
||||||
:global CertRenewPass {
|
|
||||||
"v3ry-s3cr3t";
|
|
||||||
"4n0th3r-s3cr3t";
|
|
||||||
}
|
|
||||||
:global CertWarnTime 2w;
|
|
||||||
:global CertIssuedExportPass {
|
|
||||||
"cert1-cn"="v3ry-s3cr3t";
|
|
||||||
"cert2-cn"="4n0th3r-s3cr3t";
|
|
||||||
}
|
|
||||||
|
|
||||||
# load custom settings from overlay
|
|
||||||
# Warning: Do *NOT* copy this code to overlay!
|
|
||||||
:do {
|
|
||||||
/system/script/run global-config-overlay;
|
|
||||||
} on-error={
|
|
||||||
:log error ("Loading configuration from overlay failed!");
|
|
||||||
}
|
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
92="Made qr-code url configurable for 'daily-psk'.";
|
92="Made qr-code url configurable for 'daily-psk'.";
|
||||||
93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'.";
|
93="Added support to backup global-config-overlay in 'backup-email' and 'backup-upload'.";
|
||||||
94="Added support for host addresses in address-list for 'ipv6-update'.";
|
94="Added support for host addresses in address-list for 'ipv6-update'.";
|
||||||
|
95="Renamed script files in repository, running migration. No user interaction is required.";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Migration steps to be applied on script updates
|
# Migration steps to be applied on script updates
|
||||||
|
@ -118,4 +119,5 @@
|
||||||
81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };";
|
81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };";
|
||||||
82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };";
|
82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };";
|
||||||
84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }";
|
84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }";
|
||||||
|
95=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"\\\\.rsc\\\$\" source~\"^#!rsc by RouterOS\\n\" ] do={ /system/script/set \$Script name=[ \$CharacterReplace [ get \$Script name ] \".rsc\" \"\" ]; }; \$ScriptInstallUpdate;";
|
||||||
};
|
};
|
||||||
|
|
220
global-config.rsc
Normal file
220
global-config.rsc
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: global-config
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# global configuration
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/
|
||||||
|
|
||||||
|
# Set this to 'true' to disable news and change notifications.
|
||||||
|
:global NoNewsAndChangesNotification false;
|
||||||
|
|
||||||
|
# Add extra text (or emojis) in notification tags.
|
||||||
|
:global IdentityExtra "";
|
||||||
|
|
||||||
|
# This is used for DNS and backup file.
|
||||||
|
:global Domain "example.com";
|
||||||
|
:global HostNameInZone true;
|
||||||
|
:global PrefixInZone true;
|
||||||
|
:global ServerNameInZone false;
|
||||||
|
|
||||||
|
# You can send e-mail notifications. Configure the system's mail settings
|
||||||
|
# (/tool/e-mail), then install the module:
|
||||||
|
# $ScriptInstallUpdate mod/notification-email
|
||||||
|
# The to-address needs to be filled; cc-address can be empty, one address
|
||||||
|
# or a comma separated list of addresses.
|
||||||
|
:global EmailGeneralTo "";
|
||||||
|
:global EmailGeneralCc "";
|
||||||
|
#:global EmailGeneralTo "mail@example.com";
|
||||||
|
#:global EmailGeneralCc "another@example.com,third@example.com";
|
||||||
|
|
||||||
|
# You can send Telegram notifications. Register a bot
|
||||||
|
# and add the token and chat ids here, then install the module:
|
||||||
|
# $ScriptInstallUpdate mod/notification-telegram
|
||||||
|
:global TelegramTokenId "";
|
||||||
|
:global TelegramChatId "";
|
||||||
|
#:global TelegramTokenId "123456:ABCDEF-GHI";
|
||||||
|
#:global TelegramChatId "12345678";
|
||||||
|
# Using telegram-chat you have to define trusted chat ids (not group ids!)
|
||||||
|
# or user names. Groups allow to chat with devices simultaneously.
|
||||||
|
#:global TelegramChatIdsTrusted {
|
||||||
|
# "12345678";
|
||||||
|
# "example_user";
|
||||||
|
#};
|
||||||
|
:global TelegramChatGroups "(all)";
|
||||||
|
#:global TelegramChatGroups "(all|home|office)";
|
||||||
|
# This is whether or not to send Telegram messages with fixed-width font.
|
||||||
|
:global TelegramFixedWidthFont true;
|
||||||
|
|
||||||
|
# You can send Matrix notifications. Configure these settings and
|
||||||
|
# install the module:
|
||||||
|
# $ScriptInstallUpdate mod/notification-matrix
|
||||||
|
:global MatrixHomeServer "";
|
||||||
|
:global MatrixAccessToken "";
|
||||||
|
:global MatrixRoom "";
|
||||||
|
#:global MatrixHomeServer "matrix.org";
|
||||||
|
#:global MatrixAccessToken "123456ABCDEFGHI...";
|
||||||
|
#:global MatrixRoom "!example:matrix.org";
|
||||||
|
|
||||||
|
# It is possible to override e-mail, Telegram and Matrix setting for every
|
||||||
|
# script. This is done in arrays, where 'Override' is appended to the
|
||||||
|
# variable name, like this:
|
||||||
|
#:global EmailGeneralToOverride {
|
||||||
|
# "check-certificates"="override@example.com";
|
||||||
|
# "backup-email"="backup@example.com";
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Toggle this to disable symbols in notifications.
|
||||||
|
:global NotificationsWithSymbols true;
|
||||||
|
# Toggle this to disable color output in terminal/cli.
|
||||||
|
:global TerminalColorOutput true;
|
||||||
|
|
||||||
|
# This defines what backups to generate and what password to use.
|
||||||
|
:global BackupSendBinary false;
|
||||||
|
:global BackupSendExport true;
|
||||||
|
:global BackupSendGlobalConfig true;
|
||||||
|
:global BackupPassword "v3ry-s3cr3t";
|
||||||
|
:global BackupRandomDelay 0;
|
||||||
|
# These credentials are used to upload backup and config export files.
|
||||||
|
# SFTP authentication is tricky, you may have to limit authentication
|
||||||
|
# methods for your SSH server.
|
||||||
|
:global BackupUploadUrl "sftp://example.com/backup/";
|
||||||
|
:global BackupUploadUser "mikrotik";
|
||||||
|
:global BackupUploadPass "v3ry-s3cr3t";
|
||||||
|
|
||||||
|
# This defines what log messages to filter or include by topic or message
|
||||||
|
# text. Regular expressions are supported. Do *NOT* set an empty string,
|
||||||
|
# that will filter or include everything!
|
||||||
|
# These are filters, so excluding messages from forwarding.
|
||||||
|
:global LogForwardFilter "(debug|info)";
|
||||||
|
:global LogForwardFilterMessage [];
|
||||||
|
#:global LogForwardFilterMessage "message text";
|
||||||
|
#:global LogForwardFilterMessage "(message text|another text|...)";
|
||||||
|
# ... and another setting with reverse logic. This includes messages even
|
||||||
|
# if filtered above.
|
||||||
|
:global LogForwardInclude [];
|
||||||
|
:global LogForwardIncludeMessage [];
|
||||||
|
#:global LogForwardInclude "account";
|
||||||
|
#:global LogForwardIncludeMessage "message text";
|
||||||
|
|
||||||
|
# Specify an address to enable auto update to version assumed safe.
|
||||||
|
# The configured channel (bugfix, current, release-candidate) is appended.
|
||||||
|
:global SafeUpdateUrl "";
|
||||||
|
#:global SafeUpdateUrl "https://example.com/ros/safe-update/";
|
||||||
|
# Allow to install patch updates automatically.
|
||||||
|
:global SafeUpdatePatch false;
|
||||||
|
# Allow to install updates automatically if seen in neighbor list.
|
||||||
|
:global SafeUpdateNeighbor false;
|
||||||
|
# Install *ALL* updates automatically!
|
||||||
|
# Set to all upper-case "Yes, please!" to enable.
|
||||||
|
:global SafeUpdateAll "no";
|
||||||
|
|
||||||
|
# These thresholds control when to send health notification
|
||||||
|
# on temperature and voltage.
|
||||||
|
:global CheckHealthTemperature {
|
||||||
|
temperature=50;
|
||||||
|
cpu-temperature=70;
|
||||||
|
board-temperature1=50;
|
||||||
|
board-temperature2=50;
|
||||||
|
}
|
||||||
|
# This is deviation on recovery threshold against notification flooding.
|
||||||
|
:global CheckHealthTemperatureDeviation 3;
|
||||||
|
:global CheckHealthVoltageLow 115;
|
||||||
|
:global CheckHealthVoltagePercent 10;
|
||||||
|
|
||||||
|
# Access-list entries matching this comment are updated
|
||||||
|
# with daily pseudo-random PSK.
|
||||||
|
:global DailyPskMatchComment "Daily PSK";
|
||||||
|
:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi";
|
||||||
|
:global DailyPskSecrets {
|
||||||
|
{ "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold";
|
||||||
|
"Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite";
|
||||||
|
"Evasive"; "Faded"; "Flat"; "Future"; "Grandiose";
|
||||||
|
"Hanging"; "Humorous"; "Interesting"; "Magenta";
|
||||||
|
"Magnificent"; "Numerous"; "Optimal"; "Pathetic";
|
||||||
|
"Possessive"; "Remarkable"; "Rightful"; "Ruthless";
|
||||||
|
"Stale"; "Unusual"; "Useless"; "Various" };
|
||||||
|
{ "Adhesive"; "Amusing"; "Astonishing"; "Frantic";
|
||||||
|
"Kindhearted"; "Limping"; "Roasted"; "Robust";
|
||||||
|
"Staking"; "Thundering"; "Ultra"; "Unreal" };
|
||||||
|
{ "Belief"; "Button"; "Curtain"; "Edge"; "Jewel";
|
||||||
|
"String"; "Whistle" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run different commands with multiple mode-button presses.
|
||||||
|
:global ModeButton {
|
||||||
|
1="/system/script/run leds-toggle-mode;";
|
||||||
|
2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");";
|
||||||
|
3="/system/shutdown;";
|
||||||
|
4="/system/reboot;";
|
||||||
|
5=":global BridgePortVlan; \$BridgePortVlan alt;";
|
||||||
|
# add more here...
|
||||||
|
};
|
||||||
|
# This led gives visual feedback if type is 'on' or 'off'.
|
||||||
|
:global ModeButtonLED "user-led";
|
||||||
|
|
||||||
|
# Run commands on SMS action.
|
||||||
|
:global SmsAction {
|
||||||
|
bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;";
|
||||||
|
reboot="/system/reboot;";
|
||||||
|
shutdown="/system/shutdown;";
|
||||||
|
# add more here...
|
||||||
|
};
|
||||||
|
|
||||||
|
# Run commands by hooking into SMS forward.
|
||||||
|
:global SmsForwardHooks {
|
||||||
|
{ match="magic string";
|
||||||
|
allowed-number="12345678";
|
||||||
|
command="/system/script/run ..." };
|
||||||
|
# add more here...
|
||||||
|
};
|
||||||
|
|
||||||
|
# This is the address used to send gps data to.
|
||||||
|
:global GpsTrackUrl "https://example.com/index.php";
|
||||||
|
|
||||||
|
# Enable this to fetch scripts from given url.
|
||||||
|
:global ScriptUpdatesFetch true;
|
||||||
|
:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/";
|
||||||
|
# alternative urls - main: stable code - next: currently in development
|
||||||
|
#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/";
|
||||||
|
#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/";
|
||||||
|
#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/";
|
||||||
|
#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/";
|
||||||
|
:global ScriptUpdatesUrlSuffix "";
|
||||||
|
# use next branch with default url (git.eworm.de)
|
||||||
|
#:global ScriptUpdatesUrlSuffix "\?h=next";
|
||||||
|
|
||||||
|
# Use this for defaults with $ScriptRunOnce
|
||||||
|
# Install module with:
|
||||||
|
# $ScriptInstallUpdate mod/scriptrunonce
|
||||||
|
:global ScriptRunOnceBaseUrl "";
|
||||||
|
:global ScriptRunOnceUrlSuffix "";
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/#donate
|
||||||
|
# Enable this to silence donation hint.
|
||||||
|
:global IDonate false;
|
||||||
|
|
||||||
|
# Use this for certificate auto-renew
|
||||||
|
:global CertRenewUrl "";
|
||||||
|
#:global CertRenewUrl "https://example.com/certificates/";
|
||||||
|
:global CertRenewTime 3w;
|
||||||
|
:global CertRenewPass {
|
||||||
|
"v3ry-s3cr3t";
|
||||||
|
"4n0th3r-s3cr3t";
|
||||||
|
}
|
||||||
|
:global CertWarnTime 2w;
|
||||||
|
:global CertIssuedExportPass {
|
||||||
|
"cert1-cn"="v3ry-s3cr3t";
|
||||||
|
"cert2-cn"="4n0th3r-s3cr3t";
|
||||||
|
}
|
||||||
|
|
||||||
|
# load custom settings from overlay
|
||||||
|
# Warning: Do *NOT* copy this code to overlay!
|
||||||
|
:do {
|
||||||
|
/system/script/run global-config-overlay;
|
||||||
|
} on-error={
|
||||||
|
:log error ("Loading configuration from overlay failed!");
|
||||||
|
}
|
1059
global-functions
1059
global-functions
File diff suppressed because it is too large
Load diff
1292
global-functions.rsc
Normal file
1292
global-functions.rsc
Normal file
File diff suppressed because it is too large
Load diff
10
global-wait
10
global-wait
|
@ -1,11 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: global-wait
|
|
||||||
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# wait for global-functions to finish
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md
|
|
||||||
|
|
||||||
:local 0 "global-wait";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
11
global-wait.rsc
Normal file
11
global-wait.rsc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: global-wait
|
||||||
|
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# wait for global-functions to finish
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md
|
||||||
|
|
||||||
|
:local 0 "global-wait";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
33
gps-track
33
gps-track
|
@ -1,34 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: gps-track
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# track gps data by sending json data to http server
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md
|
|
||||||
|
|
||||||
:local 0 "gps-track";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global GpsTrackUrl;
|
|
||||||
:global Identity;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:local CoordinateFormat [ /system/gps/get coordinate-format ];
|
|
||||||
:local Gps [ /system/gps/monitor once as-value ];
|
|
||||||
|
|
||||||
:if ($Gps->"valid" = true) do={
|
|
||||||
/tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \
|
|
||||||
http-method=post http-header-field="Content-Type: application/json" \
|
|
||||||
http-data=("{" . \
|
|
||||||
"\"lat\":\"" . ($Gps->"latitude") . "\"," . \
|
|
||||||
"\"lon\":\"" . ($Gps->"longitude") . "\"," . \
|
|
||||||
"\"identity\":\"" . $Identity . "\"" . \
|
|
||||||
"}") as-value;
|
|
||||||
$LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \
|
|
||||||
"lat: " . ($Gps->"latitude") . " " . \
|
|
||||||
"lon: " . ($Gps->"longitude")) false;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("GPS data not valid.") false;
|
|
||||||
}
|
|
||||||
|
|
34
gps-track.rsc
Normal file
34
gps-track.rsc
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: gps-track
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# track gps data by sending json data to http server
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md
|
||||||
|
|
||||||
|
:local 0 "gps-track";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global GpsTrackUrl;
|
||||||
|
:global Identity;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:local CoordinateFormat [ /system/gps/get coordinate-format ];
|
||||||
|
:local Gps [ /system/gps/monitor once as-value ];
|
||||||
|
|
||||||
|
:if ($Gps->"valid" = true) do={
|
||||||
|
/tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \
|
||||||
|
http-method=post http-header-field="Content-Type: application/json" \
|
||||||
|
http-data=("{" . \
|
||||||
|
"\"lat\":\"" . ($Gps->"latitude") . "\"," . \
|
||||||
|
"\"lon\":\"" . ($Gps->"longitude") . "\"," . \
|
||||||
|
"\"identity\":\"" . $Identity . "\"" . \
|
||||||
|
"}") as-value;
|
||||||
|
$LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \
|
||||||
|
"lat: " . ($Gps->"latitude") . " " . \
|
||||||
|
"lon: " . ($Gps->"longitude")) false;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("GPS data not valid.") false;
|
||||||
|
}
|
|
@ -1,72 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: hotspot-to-wpa
|
|
||||||
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# add private WPA passphrase after hotspot login
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md
|
|
||||||
|
|
||||||
:local 0 "hotspot-to-wpa";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
|
|
||||||
:local MacAddress $"mac-address";
|
|
||||||
:local UserName $username;
|
|
||||||
:local Date [ /system/clock/get date ];
|
|
||||||
:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ];
|
|
||||||
:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ];
|
|
||||||
:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ];
|
|
||||||
|
|
||||||
:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={
|
|
||||||
/caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes;
|
|
||||||
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false;
|
|
||||||
}
|
|
||||||
:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0);
|
|
||||||
|
|
||||||
:if ([ :len [ /caps-man/access-list/find where \
|
|
||||||
comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={
|
|
||||||
/caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore;
|
|
||||||
$LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false;
|
|
||||||
}
|
|
||||||
:local Template [ /caps-man/access-list/get ([ find where \
|
|
||||||
comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ];
|
|
||||||
|
|
||||||
:if ($Template->"action" = "reject") do={
|
|
||||||
$LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
# allow login page to load
|
|
||||||
:delay 1s;
|
|
||||||
|
|
||||||
$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \
|
|
||||||
" (user " . $UserName . ").") false;
|
|
||||||
/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ];
|
|
||||||
/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \
|
|
||||||
mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore;
|
|
||||||
|
|
||||||
:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \
|
|
||||||
comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ];
|
|
||||||
:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ];
|
|
||||||
:if ([ :len $PrivatePassphrase ] > 0) do={
|
|
||||||
:if ($PrivatePassphrase = "ignore") do={
|
|
||||||
/caps-man/access-list/set $Entry !private-passphrase;
|
|
||||||
} else={
|
|
||||||
/caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ];
|
|
||||||
:if ([ :len $SsidRegexp ] > 0) do={
|
|
||||||
/caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp;
|
|
||||||
}
|
|
||||||
:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ];
|
|
||||||
:if ([ :len $VlanId ] > 0) do={
|
|
||||||
/caps-man/access-list/set $Entry vlan-id=$VlanId;
|
|
||||||
}
|
|
||||||
:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ];
|
|
||||||
:if ([ :len $VlanMode] > 0) do={
|
|
||||||
/caps-man/access-list/set $Entry vlan-mode=$VlanMode;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,51 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: hotspot-to-wpa-cleanup
|
|
||||||
# Copyright (c) 2021-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# provides: lease-script, order=80
|
# dummy for migration
|
||||||
#
|
|
||||||
# manage and clean up private WPA passphrase after hotspot login
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md
|
|
||||||
|
|
||||||
:local 0 "hotspot-to-wpa-cleanup";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
|
|
||||||
$ScriptLock $0 false 10;
|
|
||||||
|
|
||||||
:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={
|
|
||||||
:local ClientVal [ /caps-man/registration-table/get $Client ];
|
|
||||||
:local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \
|
|
||||||
mac-address=($ClientVal->"mac-address") ];
|
|
||||||
:if ([ :len $Lease ] > 0) do={
|
|
||||||
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \
|
|
||||||
" connected to WPA, making lease static.") false;
|
|
||||||
/ip/dhcp-server/lease/make-static $Lease;
|
|
||||||
/ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \
|
|
||||||
!(comment~[ /system/clock/get date ]) ] do={
|
|
||||||
:local ClientVal [ /caps-man/access-list/get $Client ];
|
|
||||||
:if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \
|
|
||||||
mac-address=($ClientVal->"mac-address") ] ] = 0) do={
|
|
||||||
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \
|
|
||||||
" did not connect to WPA, removing from access list.") false;
|
|
||||||
/caps-man/access-list/remove $Client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \
|
|
||||||
last-seen>4w comment~"^hotspot-to-wpa:" ] do={
|
|
||||||
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
|
||||||
$LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \
|
|
||||||
" was not seen for long time, removing.") false;
|
|
||||||
/caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \
|
|
||||||
mac-address=($LeaseVal->"mac-address") ];
|
|
||||||
/ip/dhcp-server/lease/remove $Lease;
|
|
||||||
}
|
|
||||||
|
|
51
hotspot-to-wpa-cleanup.rsc
Normal file
51
hotspot-to-wpa-cleanup.rsc
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: hotspot-to-wpa-cleanup
|
||||||
|
# Copyright (c) 2021-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# provides: lease-script, order=80
|
||||||
|
#
|
||||||
|
# manage and clean up private WPA passphrase after hotspot login
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md
|
||||||
|
|
||||||
|
:local 0 "hotspot-to-wpa-cleanup";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
|
||||||
|
$ScriptLock $0 false 10;
|
||||||
|
|
||||||
|
:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={
|
||||||
|
:local ClientVal [ /caps-man/registration-table/get $Client ];
|
||||||
|
:local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \
|
||||||
|
mac-address=($ClientVal->"mac-address") ];
|
||||||
|
:if ([ :len $Lease ] > 0) do={
|
||||||
|
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \
|
||||||
|
" connected to WPA, making lease static.") false;
|
||||||
|
/ip/dhcp-server/lease/make-static $Lease;
|
||||||
|
/ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \
|
||||||
|
!(comment~[ /system/clock/get date ]) ] do={
|
||||||
|
:local ClientVal [ /caps-man/access-list/get $Client ];
|
||||||
|
:if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \
|
||||||
|
mac-address=($ClientVal->"mac-address") ] ] = 0) do={
|
||||||
|
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \
|
||||||
|
" did not connect to WPA, removing from access list.") false;
|
||||||
|
/caps-man/access-list/remove $Client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \
|
||||||
|
last-seen>4w comment~"^hotspot-to-wpa:" ] do={
|
||||||
|
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
|
||||||
|
$LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \
|
||||||
|
" was not seen for long time, removing.") false;
|
||||||
|
/caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \
|
||||||
|
mac-address=($LeaseVal->"mac-address") ];
|
||||||
|
/ip/dhcp-server/lease/remove $Lease;
|
||||||
|
}
|
72
hotspot-to-wpa.rsc
Normal file
72
hotspot-to-wpa.rsc
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: hotspot-to-wpa
|
||||||
|
# Copyright (c) 2019-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# add private WPA passphrase after hotspot login
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md
|
||||||
|
|
||||||
|
:local 0 "hotspot-to-wpa";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
|
||||||
|
:local MacAddress $"mac-address";
|
||||||
|
:local UserName $username;
|
||||||
|
:local Date [ /system/clock/get date ];
|
||||||
|
:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ];
|
||||||
|
:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ];
|
||||||
|
:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ];
|
||||||
|
|
||||||
|
:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={
|
||||||
|
/caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes;
|
||||||
|
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false;
|
||||||
|
}
|
||||||
|
:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0);
|
||||||
|
|
||||||
|
:if ([ :len [ /caps-man/access-list/find where \
|
||||||
|
comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={
|
||||||
|
/caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore;
|
||||||
|
$LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false;
|
||||||
|
}
|
||||||
|
:local Template [ /caps-man/access-list/get ([ find where \
|
||||||
|
comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ];
|
||||||
|
|
||||||
|
:if ($Template->"action" = "reject") do={
|
||||||
|
$LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# allow login page to load
|
||||||
|
:delay 1s;
|
||||||
|
|
||||||
|
$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \
|
||||||
|
" (user " . $UserName . ").") false;
|
||||||
|
/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ];
|
||||||
|
/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \
|
||||||
|
mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore;
|
||||||
|
|
||||||
|
:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \
|
||||||
|
comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ];
|
||||||
|
:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ];
|
||||||
|
:if ([ :len $PrivatePassphrase ] > 0) do={
|
||||||
|
:if ($PrivatePassphrase = "ignore") do={
|
||||||
|
/caps-man/access-list/set $Entry !private-passphrase;
|
||||||
|
} else={
|
||||||
|
/caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ];
|
||||||
|
:if ([ :len $SsidRegexp ] > 0) do={
|
||||||
|
/caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp;
|
||||||
|
}
|
||||||
|
:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ];
|
||||||
|
:if ([ :len $VlanId ] > 0) do={
|
||||||
|
/caps-man/access-list/set $Entry vlan-id=$VlanId;
|
||||||
|
}
|
||||||
|
:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ];
|
||||||
|
:if ([ :len $VlanMode] > 0) do={
|
||||||
|
/caps-man/access-list/set $Entry vlan-mode=$VlanMode;
|
||||||
|
}
|
|
@ -1,18 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: ip-addr-bridge
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# enable or disable ip addresses based on bridge port state
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md
|
|
||||||
|
|
||||||
:foreach Bridge in=[ /interface/bridge/find ] do={
|
|
||||||
:local BrName [ /interface/bridge/get $Bridge name ];
|
|
||||||
:if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={
|
|
||||||
:if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={
|
|
||||||
/ip/address/disable [ find where !dynamic interface=$BrName ];
|
|
||||||
} else={
|
|
||||||
/ip/address/enable [ find where !dynamic interface=$BrName ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
18
ip-addr-bridge.rsc
Normal file
18
ip-addr-bridge.rsc
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: ip-addr-bridge
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# enable or disable ip addresses based on bridge port state
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md
|
||||||
|
|
||||||
|
:foreach Bridge in=[ /interface/bridge/find ] do={
|
||||||
|
:local BrName [ /interface/bridge/get $Bridge name ];
|
||||||
|
:if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={
|
||||||
|
:if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={
|
||||||
|
/ip/address/disable [ find where !dynamic interface=$BrName ];
|
||||||
|
} else={
|
||||||
|
/ip/address/enable [ find where !dynamic interface=$BrName ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
ipsec-to-dns
68
ipsec-to-dns
|
@ -1,69 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: ipsec-to-dns
|
|
||||||
# Copyright (c) 2021-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# and add/remove/update DNS entries from IPSec mode-config
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md
|
|
||||||
|
|
||||||
:local 0 "ipsec-to-dns";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Domain;
|
|
||||||
:global HostNameInZone;
|
|
||||||
:global Identity;
|
|
||||||
:global PrefixInZone;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global EscapeForRegEx;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:local Zone \
|
|
||||||
([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \
|
|
||||||
[ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain);
|
|
||||||
:local Ttl 5m;
|
|
||||||
:local CommentPrefix ("managed by " . $0 . " for ");
|
|
||||||
:local CommentString ("--- " . $0 . " above ---");
|
|
||||||
|
|
||||||
:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={
|
|
||||||
/ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes;
|
|
||||||
$LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false;
|
|
||||||
}
|
|
||||||
:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0);
|
|
||||||
|
|
||||||
:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={
|
|
||||||
:local DnsRecordVal [ /ip/dns/static/get $DnsRecord ];
|
|
||||||
:local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ];
|
|
||||||
:if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \
|
|
||||||
dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false;
|
|
||||||
} else={
|
|
||||||
:local Found false;
|
|
||||||
$LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false;
|
|
||||||
/ip/dns/static/remove $DnsRecord;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={
|
|
||||||
:local PeerVal [ /ip/ipsec/active-peers/get $Peer ];
|
|
||||||
:local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ];
|
|
||||||
:local Comment ($CommentPrefix . $PeerId);
|
|
||||||
:local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ];
|
|
||||||
|
|
||||||
:local Fqdn ($HostName . "." . $Zone);
|
|
||||||
:local DnsRecord [ /ip/dns/static/find where name=$Fqdn ];
|
|
||||||
:if ([ :len $DnsRecord ] > 0) do={
|
|
||||||
:local DnsIp [ /ip/dns/static/get $DnsRecord address ];
|
|
||||||
:if ($DnsIp = $PeerVal->"dynamic-address") do={
|
|
||||||
$LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false;
|
|
||||||
/ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false;
|
|
||||||
/ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
69
ipsec-to-dns.rsc
Normal file
69
ipsec-to-dns.rsc
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: ipsec-to-dns
|
||||||
|
# Copyright (c) 2021-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# and add/remove/update DNS entries from IPSec mode-config
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md
|
||||||
|
|
||||||
|
:local 0 "ipsec-to-dns";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Domain;
|
||||||
|
:global HostNameInZone;
|
||||||
|
:global Identity;
|
||||||
|
:global PrefixInZone;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global EscapeForRegEx;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:local Zone \
|
||||||
|
([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \
|
||||||
|
[ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain);
|
||||||
|
:local Ttl 5m;
|
||||||
|
:local CommentPrefix ("managed by " . $0 . " for ");
|
||||||
|
:local CommentString ("--- " . $0 . " above ---");
|
||||||
|
|
||||||
|
:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={
|
||||||
|
/ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes;
|
||||||
|
$LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false;
|
||||||
|
}
|
||||||
|
:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0);
|
||||||
|
|
||||||
|
:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={
|
||||||
|
:local DnsRecordVal [ /ip/dns/static/get $DnsRecord ];
|
||||||
|
:local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ];
|
||||||
|
:if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \
|
||||||
|
dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false;
|
||||||
|
} else={
|
||||||
|
:local Found false;
|
||||||
|
$LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false;
|
||||||
|
/ip/dns/static/remove $DnsRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={
|
||||||
|
:local PeerVal [ /ip/ipsec/active-peers/get $Peer ];
|
||||||
|
:local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ];
|
||||||
|
:local Comment ($CommentPrefix . $PeerId);
|
||||||
|
:local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ];
|
||||||
|
|
||||||
|
:local Fqdn ($HostName . "." . $Zone);
|
||||||
|
:local DnsRecord [ /ip/dns/static/find where name=$Fqdn ];
|
||||||
|
:if ([ :len $DnsRecord ] > 0) do={
|
||||||
|
:local DnsIp [ /ip/dns/static/get $DnsRecord address ];
|
||||||
|
:if ($DnsIp = $PeerVal->"dynamic-address") do={
|
||||||
|
$LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false;
|
||||||
|
/ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false;
|
||||||
|
/ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
||||||
|
}
|
||||||
|
}
|
75
ipv6-update
75
ipv6-update
|
@ -1,76 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: ipv6-update
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# update firewall and dns settings on IPv6 prefix change
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md
|
|
||||||
|
|
||||||
:local 0 "ipv6-update";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local PdPrefix $"pd-prefix";
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
|
|
||||||
:if ([ :typeof $PdPrefix ] = "nothing") do={
|
|
||||||
$LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ];
|
|
||||||
:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={
|
|
||||||
/ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool);
|
|
||||||
$LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false;
|
|
||||||
}
|
|
||||||
:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ];
|
|
||||||
:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ];
|
|
||||||
|
|
||||||
:if ($OldPrefix != $PdPrefix) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false;
|
|
||||||
/ipv6/firewall/address-list/set address=$PdPrefix $AddrList;
|
|
||||||
|
|
||||||
# give the interfaces a moment to receive their addresses
|
|
||||||
:delay 2s;
|
|
||||||
|
|
||||||
:foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={
|
|
||||||
:local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ];
|
|
||||||
:local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ];
|
|
||||||
|
|
||||||
:local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ];
|
|
||||||
:if ([ :len $Prefix ] = 1) do={
|
|
||||||
:set Prefix [ /ipv6/address/get $Prefix address ];
|
|
||||||
|
|
||||||
:if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={
|
|
||||||
:set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::);
|
|
||||||
:local Address ($ListEntryVal->"address");
|
|
||||||
:local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff));
|
|
||||||
|
|
||||||
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \
|
|
||||||
" from interface " . ($Comment->"interface")) false;
|
|
||||||
/ipv6/firewall/address-list/set address=$Address $ListEntry;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \
|
|
||||||
" from interface " . ($Comment->"interface")) false;
|
|
||||||
/ipv6/firewall/address-list/set address=$Prefix $ListEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={
|
|
||||||
:local RecordVal [ /ip/dns/static/get $Record ];
|
|
||||||
:local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ];
|
|
||||||
|
|
||||||
:local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ];
|
|
||||||
:if ([ :len $Prefix ] = 1) do={
|
|
||||||
:set Prefix [ /ipv6/address/get $Prefix address ];
|
|
||||||
:set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::);
|
|
||||||
:local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff));
|
|
||||||
|
|
||||||
$LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \
|
|
||||||
($RecordVal->"regexp") . " to " . $Address) false;
|
|
||||||
/ip/dns/static/set address=$Address $Record;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
76
ipv6-update.rsc
Normal file
76
ipv6-update.rsc
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: ipv6-update
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# update firewall and dns settings on IPv6 prefix change
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md
|
||||||
|
|
||||||
|
:local 0 "ipv6-update";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:local PdPrefix $"pd-prefix";
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
|
||||||
|
:if ([ :typeof $PdPrefix ] = "nothing") do={
|
||||||
|
$LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ];
|
||||||
|
:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={
|
||||||
|
/ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool);
|
||||||
|
$LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false;
|
||||||
|
}
|
||||||
|
:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ];
|
||||||
|
:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ];
|
||||||
|
|
||||||
|
:if ($OldPrefix != $PdPrefix) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false;
|
||||||
|
/ipv6/firewall/address-list/set address=$PdPrefix $AddrList;
|
||||||
|
|
||||||
|
# give the interfaces a moment to receive their addresses
|
||||||
|
:delay 2s;
|
||||||
|
|
||||||
|
:foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={
|
||||||
|
:local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ];
|
||||||
|
:local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ];
|
||||||
|
|
||||||
|
:local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ];
|
||||||
|
:if ([ :len $Prefix ] = 1) do={
|
||||||
|
:set Prefix [ /ipv6/address/get $Prefix address ];
|
||||||
|
|
||||||
|
:if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={
|
||||||
|
:set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::);
|
||||||
|
:local Address ($ListEntryVal->"address");
|
||||||
|
:local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff));
|
||||||
|
|
||||||
|
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 host address " . $Address . \
|
||||||
|
" from interface " . ($Comment->"interface")) false;
|
||||||
|
/ipv6/firewall/address-list/set address=$Address $ListEntry;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \
|
||||||
|
" from interface " . ($Comment->"interface")) false;
|
||||||
|
/ipv6/firewall/address-list/set address=$Prefix $ListEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={
|
||||||
|
:local RecordVal [ /ip/dns/static/get $Record ];
|
||||||
|
:local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ];
|
||||||
|
|
||||||
|
:local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ];
|
||||||
|
:if ([ :len $Prefix ] = 1) do={
|
||||||
|
:set Prefix [ /ipv6/address/get $Prefix address ];
|
||||||
|
:set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::);
|
||||||
|
:local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff));
|
||||||
|
|
||||||
|
$LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \
|
||||||
|
($RecordVal->"regexp") . " to " . $Address) false;
|
||||||
|
/ip/dns/static/set address=$Address $Record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
lease-script
50
lease-script
|
@ -1,51 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: lease-script
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# run scripts on DHCP lease
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md
|
|
||||||
|
|
||||||
:local 0 "lease-script";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Grep;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
:global ScriptLock;
|
|
||||||
|
|
||||||
:if ([ :typeof $leaseActIP ] = "nothing" || \
|
|
||||||
[ :typeof $leaseActMAC ] = "nothing" || \
|
|
||||||
[ :typeof $leaseServerName ] = "nothing" || \
|
|
||||||
[ :typeof $leaseBound ] = "nothing") do={
|
|
||||||
$LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \
|
|
||||||
"de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false;
|
|
||||||
|
|
||||||
$ScriptLock $0 false 10;
|
|
||||||
|
|
||||||
:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={
|
|
||||||
$LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local RunOrder ({});
|
|
||||||
|
|
||||||
:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={
|
|
||||||
:local ScriptVal [ /system/script/get $Script ];
|
|
||||||
:local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ];
|
|
||||||
|
|
||||||
:set ($RunOrder->($Store->"order")) ($ScriptVal->"name");
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Order,Script in=$RunOrder do={
|
|
||||||
:do {
|
|
||||||
$LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false;
|
|
||||||
/system/script/run $Script;
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
51
lease-script.rsc
Normal file
51
lease-script.rsc
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: lease-script
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# run scripts on DHCP lease
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md
|
||||||
|
|
||||||
|
:local 0 "lease-script";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Grep;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
:global ScriptLock;
|
||||||
|
|
||||||
|
:if ([ :typeof $leaseActIP ] = "nothing" || \
|
||||||
|
[ :typeof $leaseActMAC ] = "nothing" || \
|
||||||
|
[ :typeof $leaseServerName ] = "nothing" || \
|
||||||
|
[ :typeof $leaseBound ] = "nothing") do={
|
||||||
|
$LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \
|
||||||
|
"de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false;
|
||||||
|
|
||||||
|
$ScriptLock $0 false 10;
|
||||||
|
|
||||||
|
:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={
|
||||||
|
$LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local RunOrder ({});
|
||||||
|
|
||||||
|
:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={
|
||||||
|
:local ScriptVal [ /system/script/get $Script ];
|
||||||
|
:local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") "# provides: lease-script, " ] ];
|
||||||
|
|
||||||
|
:set ($RunOrder->($Store->"order")) ($ScriptVal->"name");
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Order,Script in=$RunOrder do={
|
||||||
|
:do {
|
||||||
|
$LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false;
|
||||||
|
/system/script/run $Script;
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: leds-day-mode
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# enable LEDs
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
|
||||||
|
|
||||||
/system/leds/settings/set all-leds-off=never;
|
|
||||||
|
|
9
leds-day-mode.rsc
Normal file
9
leds-day-mode.rsc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: leds-day-mode
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# enable LEDs
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
||||||
|
|
||||||
|
/system/leds/settings/set all-leds-off=never;
|
|
@ -1,9 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: leds-night-mode
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# disable LEDs
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
|
||||||
|
|
||||||
/system/leds/settings/set all-leds-off=immediate;
|
|
||||||
|
|
9
leds-night-mode.rsc
Normal file
9
leds-night-mode.rsc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: leds-night-mode
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# disable LEDs
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
||||||
|
|
||||||
|
/system/leds/settings/set all-leds-off=immediate;
|
|
@ -1,13 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: leds-toggle-mode
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# toggle LEDs mode
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
|
||||||
|
|
||||||
:if ([ /system/leds/settings/get all-leds-off ] = "never") do={
|
|
||||||
/system/leds/settings/set all-leds-off=immediate;
|
|
||||||
} else={
|
|
||||||
/system/leds/settings/set all-leds-off=never;
|
|
||||||
}
|
|
||||||
|
|
13
leds-toggle-mode.rsc
Normal file
13
leds-toggle-mode.rsc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: leds-toggle-mode
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# toggle LEDs mode
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md
|
||||||
|
|
||||||
|
:if ([ /system/leds/settings/get all-leds-off ] = "never") do={
|
||||||
|
/system/leds/settings/set all-leds-off=immediate;
|
||||||
|
} else={
|
||||||
|
/system/leds/settings/set all-leds-off=never;
|
||||||
|
}
|
89
log-forward
89
log-forward
|
@ -1,90 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: log-forward
|
|
||||||
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# forward log messages via notification
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md
|
|
||||||
|
|
||||||
:local 0 "log-forward";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
:global LogForwardFilter;
|
|
||||||
:global LogForwardFilterMessage;
|
|
||||||
:global LogForwardInclude;
|
|
||||||
:global LogForwardIncludeMessage;
|
|
||||||
:global LogForwardLast;
|
|
||||||
:global LogForwardRateLimit;
|
|
||||||
:global NotificationsWithSymbols;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global HexToNum;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogForwardFilterLogForwarding;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ScriptLock;
|
|
||||||
:global SendNotification2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
|
|
||||||
:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={
|
|
||||||
:set LogForwardRateLimit 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($LogForwardRateLimit > 30) do={
|
|
||||||
:set LogForwardRateLimit ($LogForwardRateLimit - 1);
|
|
||||||
$LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Count 0;
|
|
||||||
:local Duplicates false;
|
|
||||||
:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ];
|
|
||||||
:local Messages "";
|
|
||||||
:local Warning false;
|
|
||||||
:local MessageVal;
|
|
||||||
:local MessageDups ({});
|
|
||||||
|
|
||||||
:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ];
|
|
||||||
:foreach Message in=[ /log/find where (!(message="") and \
|
|
||||||
!(message~$LogForwardFilterLogForwardingCached) and \
|
|
||||||
!(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \
|
|
||||||
topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={
|
|
||||||
:set MessageVal [ /log/get $Message ];
|
|
||||||
|
|
||||||
:if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={
|
|
||||||
:local DupCount ($MessageDups->($MessageVal->"message"));
|
|
||||||
:if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={
|
|
||||||
:set Warning true;
|
|
||||||
}
|
|
||||||
: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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($Count > 0) do={
|
|
||||||
:set LogForwardRateLimit ($LogForwardRateLimit + 10);
|
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; \
|
|
||||||
subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \
|
|
||||||
"Log Forwarding"); \
|
|
||||||
message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \
|
|
||||||
("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \
|
|
||||||
[ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \
|
|
||||||
[ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \
|
|
||||||
"\n" . $Messages) });
|
|
||||||
|
|
||||||
:set LogForwardLast ($MessageVal->".id");
|
|
||||||
} else={
|
|
||||||
:if ($LogForwardRateLimit > 0) do={
|
|
||||||
:set LogForwardRateLimit ($LogForwardRateLimit - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
90
log-forward.rsc
Normal file
90
log-forward.rsc
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: log-forward
|
||||||
|
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# forward log messages via notification
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md
|
||||||
|
|
||||||
|
:local 0 "log-forward";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global LogForwardFilter;
|
||||||
|
:global LogForwardFilterMessage;
|
||||||
|
:global LogForwardInclude;
|
||||||
|
:global LogForwardIncludeMessage;
|
||||||
|
:global LogForwardLast;
|
||||||
|
:global LogForwardRateLimit;
|
||||||
|
:global NotificationsWithSymbols;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global HexToNum;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogForwardFilterLogForwarding;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
|
||||||
|
:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={
|
||||||
|
:set LogForwardRateLimit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($LogForwardRateLimit > 30) do={
|
||||||
|
:set LogForwardRateLimit ($LogForwardRateLimit - 1);
|
||||||
|
$LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Count 0;
|
||||||
|
:local Duplicates false;
|
||||||
|
:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ];
|
||||||
|
:local Messages "";
|
||||||
|
:local Warning false;
|
||||||
|
:local MessageVal;
|
||||||
|
:local MessageDups ({});
|
||||||
|
|
||||||
|
:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ];
|
||||||
|
:foreach Message in=[ /log/find where (!(message="") and \
|
||||||
|
!(message~$LogForwardFilterLogForwardingCached) and \
|
||||||
|
!(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \
|
||||||
|
topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={
|
||||||
|
:set MessageVal [ /log/get $Message ];
|
||||||
|
|
||||||
|
:if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={
|
||||||
|
:local DupCount ($MessageDups->($MessageVal->"message"));
|
||||||
|
:if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={
|
||||||
|
:set Warning true;
|
||||||
|
}
|
||||||
|
: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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($Count > 0) do={
|
||||||
|
:set LogForwardRateLimit ($LogForwardRateLimit + 10);
|
||||||
|
|
||||||
|
$SendNotification2 ({ origin=$0; \
|
||||||
|
subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \
|
||||||
|
"Log Forwarding"); \
|
||||||
|
message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \
|
||||||
|
("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \
|
||||||
|
[ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \
|
||||||
|
[ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \
|
||||||
|
"\n" . $Messages) });
|
||||||
|
|
||||||
|
:set LogForwardLast ($MessageVal->".id");
|
||||||
|
} else={
|
||||||
|
:if ($LogForwardRateLimit > 0) do={
|
||||||
|
:set LogForwardRateLimit ($LogForwardRateLimit - 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/bridge-port-to
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# reset bridge ports to default bridge
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md
|
|
||||||
|
|
||||||
:global BridgePortTo;
|
|
||||||
|
|
||||||
:set BridgePortTo do={
|
|
||||||
:local BridgePortTo [ :tostr $1 ];
|
|
||||||
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
|
|
||||||
:local InterfaceReEnable ({});
|
|
||||||
:foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={
|
|
||||||
:local BridgePortVal [ /interface/bridge/port/get $BridgePort ];
|
|
||||||
:foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={
|
|
||||||
:if ($Config = $BridgePortTo) do={
|
|
||||||
:local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ];
|
|
||||||
|
|
||||||
:if ($BridgeDefault = "dhcp-client") do={
|
|
||||||
:if ([ :len $DHCPClient ] != 1) do={
|
|
||||||
$LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \
|
|
||||||
" dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true;
|
|
||||||
}
|
|
||||||
:local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ];
|
|
||||||
|
|
||||||
:if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={
|
|
||||||
$LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false;
|
|
||||||
/interface/bridge/port/disable $BridgePort;
|
|
||||||
:delay 200ms;
|
|
||||||
/ip/dhcp-client/enable $DHCPClient;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
:if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={
|
|
||||||
$LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \
|
|
||||||
" bridge " . $BridgeDefault . ", disabling dhcp client.") false;
|
|
||||||
:if ([ :len $DHCPClient ] = 1) do={
|
|
||||||
/ip/dhcp-client/disable $DHCPClient;
|
|
||||||
:delay 200ms;
|
|
||||||
}
|
|
||||||
:local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ];
|
|
||||||
:if ([ :len $Disable ] > 0) do={
|
|
||||||
/interface/ethernet/disable $Disable;
|
|
||||||
:set InterfaceReEnable ($InterfaceReEnable, $Disable);
|
|
||||||
}
|
|
||||||
/interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \
|
|
||||||
" bridge " . $BridgeDefault . ".") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:if ([ :len $InterfaceReEnable ] > 0) do={
|
|
||||||
:delay 2s;
|
|
||||||
$LogPrintExit2 info $0 ("Re-enabling interfaces...") false;
|
|
||||||
/interface/ethernet/enable $InterfaceReEnable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
65
mod/bridge-port-to.rsc
Normal file
65
mod/bridge-port-to.rsc
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/bridge-port-to
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# reset bridge ports to default bridge
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-to.md
|
||||||
|
|
||||||
|
:global BridgePortTo;
|
||||||
|
|
||||||
|
:set BridgePortTo do={
|
||||||
|
:local BridgePortTo [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
|
||||||
|
:local InterfaceReEnable ({});
|
||||||
|
:foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={
|
||||||
|
:local BridgePortVal [ /interface/bridge/port/get $BridgePort ];
|
||||||
|
:foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={
|
||||||
|
:if ($Config = $BridgePortTo) do={
|
||||||
|
:local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ];
|
||||||
|
|
||||||
|
:if ($BridgeDefault = "dhcp-client") do={
|
||||||
|
:if ([ :len $DHCPClient ] != 1) do={
|
||||||
|
$LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \
|
||||||
|
" dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true;
|
||||||
|
}
|
||||||
|
:local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ];
|
||||||
|
|
||||||
|
:if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={
|
||||||
|
$LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false;
|
||||||
|
/interface/bridge/port/disable $BridgePort;
|
||||||
|
:delay 200ms;
|
||||||
|
/ip/dhcp-client/enable $DHCPClient;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={
|
||||||
|
$LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \
|
||||||
|
" bridge " . $BridgeDefault . ", disabling dhcp client.") false;
|
||||||
|
:if ([ :len $DHCPClient ] = 1) do={
|
||||||
|
/ip/dhcp-client/disable $DHCPClient;
|
||||||
|
:delay 200ms;
|
||||||
|
}
|
||||||
|
:local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ];
|
||||||
|
:if ([ :len $Disable ] > 0) do={
|
||||||
|
/interface/ethernet/disable $Disable;
|
||||||
|
:set InterfaceReEnable ($InterfaceReEnable, $Disable);
|
||||||
|
}
|
||||||
|
/interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \
|
||||||
|
" bridge " . $BridgeDefault . ".") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ([ :len $InterfaceReEnable ] > 0) do={
|
||||||
|
:delay 2s;
|
||||||
|
$LogPrintExit2 info $0 ("Re-enabling interfaces...") false;
|
||||||
|
/interface/ethernet/enable $InterfaceReEnable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,73 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/bridge-port-vlan
|
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# manage VLANs on bridge ports
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md
|
|
||||||
|
|
||||||
:global BridgePortVlan;
|
|
||||||
|
|
||||||
:global BridgePortVlan do={
|
|
||||||
:local ConfigTo [ :tostr $1 ];
|
|
||||||
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
|
|
||||||
:local InterfaceReEnable ({});
|
|
||||||
:foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={
|
|
||||||
:local BridgePortVal [ /interface/bridge/port/get $BridgePort ];
|
|
||||||
:foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={
|
|
||||||
:if ($Config = $ConfigTo) do={
|
|
||||||
:local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ];
|
|
||||||
|
|
||||||
:if ($Vlan = "dhcp-client") do={
|
|
||||||
:if ([ :len $DHCPClient ] != 1) do={
|
|
||||||
$LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \
|
|
||||||
" dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true;
|
|
||||||
}
|
|
||||||
:local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ];
|
|
||||||
|
|
||||||
:if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={
|
|
||||||
$LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false;
|
|
||||||
/interface/bridge/port/disable $BridgePort;
|
|
||||||
:delay 200ms;
|
|
||||||
/ip/dhcp-client/enable $DHCPClient;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
:local VlanName $Vlan;
|
|
||||||
:if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={
|
|
||||||
:do {
|
|
||||||
:set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0);
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={
|
|
||||||
$LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \
|
|
||||||
" vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false;
|
|
||||||
:if ([ :len $DHCPClient ] = 1) do={
|
|
||||||
/ip/dhcp-client/disable $DHCPClient;
|
|
||||||
:delay 200ms;
|
|
||||||
}
|
|
||||||
:local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ];
|
|
||||||
:if ([ :len $Disable ] > 0) do={
|
|
||||||
/interface/ethernet/disable $Disable;
|
|
||||||
:set InterfaceReEnable ($InterfaceReEnable, $Disable);
|
|
||||||
}
|
|
||||||
/interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \
|
|
||||||
" vlan " . $Vlan . ".") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:if ([ :len $InterfaceReEnable ] > 0) do={
|
|
||||||
:delay 2s;
|
|
||||||
$LogPrintExit2 info $0 ("Re-enabling interfaces...") false;
|
|
||||||
/interface/ethernet/enable $InterfaceReEnable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
73
mod/bridge-port-vlan.rsc
Normal file
73
mod/bridge-port-vlan.rsc
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/bridge-port-vlan
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# manage VLANs on bridge ports
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/bridge-port-vlan.md
|
||||||
|
|
||||||
|
:global BridgePortVlan;
|
||||||
|
|
||||||
|
:global BridgePortVlan do={
|
||||||
|
:local ConfigTo [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
|
||||||
|
:local InterfaceReEnable ({});
|
||||||
|
:foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={
|
||||||
|
:local BridgePortVal [ /interface/bridge/port/get $BridgePort ];
|
||||||
|
:foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={
|
||||||
|
:if ($Config = $ConfigTo) do={
|
||||||
|
:local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ];
|
||||||
|
|
||||||
|
:if ($Vlan = "dhcp-client") do={
|
||||||
|
:if ([ :len $DHCPClient ] != 1) do={
|
||||||
|
$LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \
|
||||||
|
" dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true;
|
||||||
|
}
|
||||||
|
:local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ];
|
||||||
|
|
||||||
|
:if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={
|
||||||
|
$LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false;
|
||||||
|
/interface/bridge/port/disable $BridgePort;
|
||||||
|
:delay 200ms;
|
||||||
|
/ip/dhcp-client/enable $DHCPClient;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:local VlanName $Vlan;
|
||||||
|
:if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={
|
||||||
|
:do {
|
||||||
|
:set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0);
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={
|
||||||
|
$LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \
|
||||||
|
" vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false;
|
||||||
|
:if ([ :len $DHCPClient ] = 1) do={
|
||||||
|
/ip/dhcp-client/disable $DHCPClient;
|
||||||
|
:delay 200ms;
|
||||||
|
}
|
||||||
|
:local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ];
|
||||||
|
:if ([ :len $Disable ] > 0) do={
|
||||||
|
/interface/ethernet/disable $Disable;
|
||||||
|
:set InterfaceReEnable ($InterfaceReEnable, $Disable);
|
||||||
|
}
|
||||||
|
/interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \
|
||||||
|
" vlan " . $Vlan . ".") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ([ :len $InterfaceReEnable ] > 0) do={
|
||||||
|
:delay 2s;
|
||||||
|
$LogPrintExit2 info $0 ("Re-enabling interfaces...") false;
|
||||||
|
/interface/ethernet/enable $InterfaceReEnable;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/inspectvar
|
#
|
||||||
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global InspectVar;
|
|
||||||
:global InspectVarReturn;
|
|
||||||
|
|
||||||
# inspect variable and print on terminal
|
|
||||||
:set InspectVar do={
|
|
||||||
:global InspectVarReturn;
|
|
||||||
:global PrettyPrint;
|
|
||||||
|
|
||||||
$PrettyPrint [ $InspectVarReturn $1 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
# inspect variable and return formatted string
|
|
||||||
:set InspectVarReturn do={
|
|
||||||
:local Input $1;
|
|
||||||
:local Level (0 + [ :tonum $2 ]);
|
|
||||||
|
|
||||||
:global IfThenElse;
|
|
||||||
:global InspectVarReturn;
|
|
||||||
|
|
||||||
:local IndentReturn do={
|
|
||||||
:local Prefix [ :tostr $1 ];
|
|
||||||
: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);
|
|
||||||
}
|
|
||||||
|
|
||||||
:local TypeOf [ :typeof $Input ];
|
|
||||||
:local Return [ $IndentReturn "type" $TypeOf $Level ];
|
|
||||||
|
|
||||||
:if ($TypeOf = "array") do={
|
|
||||||
:foreach Key,Value in=$Input do={
|
|
||||||
:set $Return ($Return . "\n" . \
|
|
||||||
[ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \
|
|
||||||
[ $InspectVarReturn $Value ($Level + 2) ]);
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
:if ($TypeOf != "nothing") do={
|
|
||||||
:set $Return ($Return . "\n" . \
|
|
||||||
[ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \
|
|
||||||
([ :pick $Input 0 77 ] . "...") $Input ] $Level ]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:return $Return;
|
|
||||||
}
|
|
||||||
|
|
54
mod/inspectvar.rsc
Normal file
54
mod/inspectvar.rsc
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/inspectvar
|
||||||
|
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global InspectVar;
|
||||||
|
:global InspectVarReturn;
|
||||||
|
|
||||||
|
# inspect variable and print on terminal
|
||||||
|
:set InspectVar do={
|
||||||
|
:global InspectVarReturn;
|
||||||
|
:global PrettyPrint;
|
||||||
|
|
||||||
|
$PrettyPrint [ $InspectVarReturn $1 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# inspect variable and return formatted string
|
||||||
|
:set InspectVarReturn do={
|
||||||
|
:local Input $1;
|
||||||
|
:local Level (0 + [ :tonum $2 ]);
|
||||||
|
|
||||||
|
:global IfThenElse;
|
||||||
|
:global InspectVarReturn;
|
||||||
|
|
||||||
|
:local IndentReturn do={
|
||||||
|
:local Prefix [ :tostr $1 ];
|
||||||
|
: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);
|
||||||
|
}
|
||||||
|
|
||||||
|
:local TypeOf [ :typeof $Input ];
|
||||||
|
:local Return [ $IndentReturn "type" $TypeOf $Level ];
|
||||||
|
|
||||||
|
:if ($TypeOf = "array") do={
|
||||||
|
:foreach Key,Value in=$Input do={
|
||||||
|
:set $Return ($Return . "\n" . \
|
||||||
|
[ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \
|
||||||
|
[ $InspectVarReturn $Value ($Level + 2) ]);
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:if ($TypeOf != "nothing") do={
|
||||||
|
:set $Return ($Return . "\n" . \
|
||||||
|
[ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \
|
||||||
|
([ :pick $Input 0 77 ] . "...") $Input ] $Level ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:return $Return;
|
||||||
|
}
|
47
mod/ipcalc
47
mod/ipcalc
|
@ -1,46 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/ipcalc
|
#
|
||||||
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global IPCalc;
|
|
||||||
:global IPCalcReturn;
|
|
||||||
|
|
||||||
# print netmask, network, min host, max host and broadcast
|
|
||||||
:set IPCalc do={
|
|
||||||
:local Input [ :tostr $1 ];
|
|
||||||
|
|
||||||
:global IPCalcReturn;
|
|
||||||
:global PrettyPrint;
|
|
||||||
|
|
||||||
:local Values [ $IPCalcReturn $1 ];
|
|
||||||
|
|
||||||
$PrettyPrint ( \
|
|
||||||
"Address: " . $Values->"address" . "\n" . \
|
|
||||||
"Netmask: " . $Values->"netmask" . "\n" . \
|
|
||||||
"Network: " . $Values->"network" . "\n" . \
|
|
||||||
"HostMin: " . $Values->"hostmin" . "\n" . \
|
|
||||||
"HostMax: " . $Values->"hostmax" . "\n" . \
|
|
||||||
"Broadcast: " . $Values->"broadcast");
|
|
||||||
}
|
|
||||||
|
|
||||||
# calculate and return netmask, network, min host, max host and broadcast
|
|
||||||
:set IPCalcReturn do={
|
|
||||||
:local Input [ :tostr $1 ];
|
|
||||||
: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 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);
|
|
||||||
"broadcast"=($Address | ~$Mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
:return $Return;
|
|
||||||
}
|
|
||||||
|
|
46
mod/ipcalc.rsc
Normal file
46
mod/ipcalc.rsc
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/ipcalc
|
||||||
|
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global IPCalc;
|
||||||
|
:global IPCalcReturn;
|
||||||
|
|
||||||
|
# print netmask, network, min host, max host and broadcast
|
||||||
|
:set IPCalc do={
|
||||||
|
:local Input [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global IPCalcReturn;
|
||||||
|
:global PrettyPrint;
|
||||||
|
|
||||||
|
:local Values [ $IPCalcReturn $1 ];
|
||||||
|
|
||||||
|
$PrettyPrint ( \
|
||||||
|
"Address: " . $Values->"address" . "\n" . \
|
||||||
|
"Netmask: " . $Values->"netmask" . "\n" . \
|
||||||
|
"Network: " . $Values->"network" . "\n" . \
|
||||||
|
"HostMin: " . $Values->"hostmin" . "\n" . \
|
||||||
|
"HostMax: " . $Values->"hostmax" . "\n" . \
|
||||||
|
"Broadcast: " . $Values->"broadcast");
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate and return netmask, network, min host, max host and broadcast
|
||||||
|
:set IPCalcReturn do={
|
||||||
|
:local Input [ :tostr $1 ];
|
||||||
|
: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 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);
|
||||||
|
"broadcast"=($Address | ~$Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
:return $Return;
|
||||||
|
}
|
|
@ -1,206 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/notification-email
|
#
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global FlushEmailQueue;
|
|
||||||
:global LogForwardFilterLogForwarding;
|
|
||||||
:global NotificationEMailSubject;
|
|
||||||
:global NotificationFunctions;
|
|
||||||
:global QuotedPrintable;
|
|
||||||
:global SendEMail;
|
|
||||||
:global SendEMail2;
|
|
||||||
|
|
||||||
# flush e-mail queue
|
|
||||||
:set FlushEmailQueue do={
|
|
||||||
:global EmailQueue;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global IsDNSResolving;
|
|
||||||
:global IsTimeSync;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:local AllDone true;
|
|
||||||
:local QueueLen [ :len $EmailQueue ];
|
|
||||||
:local Scheduler [ /system/scheduler/find where name=$0 ];
|
|
||||||
|
|
||||||
:if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={
|
|
||||||
/system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ /tool/e-mail/get last-status ] = "in-progress") do={
|
|
||||||
$LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ $IsTimeSync ] = false) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={
|
|
||||||
$LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler;
|
|
||||||
|
|
||||||
: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={
|
|
||||||
$LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/tool/e-mail/send 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:if ($Status = "failed") do={
|
|
||||||
:set AllDone false;
|
|
||||||
:set Wait false;
|
|
||||||
}
|
|
||||||
} while=($Wait = true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={
|
|
||||||
/system/scheduler/remove $Scheduler;
|
|
||||||
:set EmailQueue;
|
|
||||||
} else={
|
|
||||||
/system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate filter for log-forward
|
|
||||||
:set LogForwardFilterLogForwarding do={
|
|
||||||
:global EscapeForRegEx;
|
|
||||||
:global NotificationEMailSubject;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
:return ("^Error sending e-mail <(" . \
|
|
||||||
[ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \
|
|
||||||
"memo" ] . "Log Forwarding") ] ] . "|" . \
|
|
||||||
[ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \
|
|
||||||
"warning-sign" ] . "Log Forwarding") ] ] . ")>:");
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate the e-mail subject
|
|
||||||
:set NotificationEMailSubject do={
|
|
||||||
:global Identity;
|
|
||||||
:global IdentityExtra;
|
|
||||||
|
|
||||||
:global QuotedPrintable;
|
|
||||||
|
|
||||||
:return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ];
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via e-mail - expects one array argument
|
|
||||||
:set ($NotificationFunctions->"email") do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global EmailGeneralTo;
|
|
||||||
:global EmailGeneralToOverride;
|
|
||||||
:global EmailGeneralCc;
|
|
||||||
:global EmailGeneralCcOverride;
|
|
||||||
:global EmailQueue;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global NotificationEMailSubject;
|
|
||||||
|
|
||||||
:local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
|
|
||||||
:local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];
|
|
||||||
|
|
||||||
:local EMailSettings [ /tool/e-mail/get ];
|
|
||||||
:if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :typeof $EmailQueue ] = "nothing") do={
|
|
||||||
:set EmailQueue ({});
|
|
||||||
}
|
|
||||||
:local Signature [ /system/note/get note ];
|
|
||||||
: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) "" ]); \
|
|
||||||
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 \
|
|
||||||
comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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 . "\?=");
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via e-mail - expects at least two string arguments
|
|
||||||
:set SendEMail do={
|
|
||||||
:global SendEMail2;
|
|
||||||
|
|
||||||
$SendEMail2 ({ subject=$1; message=$2; link=$3 });
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via e-mail - expects one array argument
|
|
||||||
:set SendEMail2 do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global NotificationFunctions;
|
|
||||||
|
|
||||||
($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification;
|
|
||||||
}
|
|
||||||
|
|
206
mod/notification-email.rsc
Normal file
206
mod/notification-email.rsc
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/notification-email
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global FlushEmailQueue;
|
||||||
|
:global LogForwardFilterLogForwarding;
|
||||||
|
:global NotificationEMailSubject;
|
||||||
|
:global NotificationFunctions;
|
||||||
|
:global QuotedPrintable;
|
||||||
|
:global SendEMail;
|
||||||
|
:global SendEMail2;
|
||||||
|
|
||||||
|
# flush e-mail queue
|
||||||
|
:set FlushEmailQueue do={
|
||||||
|
:global EmailQueue;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global IsDNSResolving;
|
||||||
|
:global IsTimeSync;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:local AllDone true;
|
||||||
|
:local QueueLen [ :len $EmailQueue ];
|
||||||
|
:local Scheduler [ /system/scheduler/find where name=$0 ];
|
||||||
|
|
||||||
|
:if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={
|
||||||
|
/system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ /tool/e-mail/get last-status ] = "in-progress") do={
|
||||||
|
$LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ $IsTimeSync ] = false) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={
|
||||||
|
$LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler;
|
||||||
|
|
||||||
|
: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={
|
||||||
|
$LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/tool/e-mail/send 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ($Status = "failed") do={
|
||||||
|
:set AllDone false;
|
||||||
|
:set Wait false;
|
||||||
|
}
|
||||||
|
} while=($Wait = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={
|
||||||
|
/system/scheduler/remove $Scheduler;
|
||||||
|
:set EmailQueue;
|
||||||
|
} else={
|
||||||
|
/system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate filter for log-forward
|
||||||
|
:set LogForwardFilterLogForwarding do={
|
||||||
|
:global EscapeForRegEx;
|
||||||
|
:global NotificationEMailSubject;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
:return ("^Error sending e-mail <(" . \
|
||||||
|
[ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \
|
||||||
|
"memo" ] . "Log Forwarding") ] ] . "|" . \
|
||||||
|
[ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \
|
||||||
|
"warning-sign" ] . "Log Forwarding") ] ] . ")>:");
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate the e-mail subject
|
||||||
|
:set NotificationEMailSubject do={
|
||||||
|
:global Identity;
|
||||||
|
:global IdentityExtra;
|
||||||
|
|
||||||
|
:global QuotedPrintable;
|
||||||
|
|
||||||
|
:return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via e-mail - expects one array argument
|
||||||
|
:set ($NotificationFunctions->"email") do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global EmailGeneralTo;
|
||||||
|
:global EmailGeneralToOverride;
|
||||||
|
:global EmailGeneralCc;
|
||||||
|
:global EmailGeneralCcOverride;
|
||||||
|
:global EmailQueue;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global NotificationEMailSubject;
|
||||||
|
|
||||||
|
:local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
|
||||||
|
:local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];
|
||||||
|
|
||||||
|
:local EMailSettings [ /tool/e-mail/get ];
|
||||||
|
:if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :typeof $EmailQueue ] = "nothing") do={
|
||||||
|
:set EmailQueue ({});
|
||||||
|
}
|
||||||
|
:local Signature [ /system/note/get note ];
|
||||||
|
: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) "" ]); \
|
||||||
|
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 \
|
||||||
|
comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 . "\?=");
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via e-mail - expects at least two string arguments
|
||||||
|
:set SendEMail do={
|
||||||
|
:global SendEMail2;
|
||||||
|
|
||||||
|
$SendEMail2 ({ subject=$1; message=$2; link=$3 });
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via e-mail - expects one array argument
|
||||||
|
:set SendEMail2 do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global NotificationFunctions;
|
||||||
|
|
||||||
|
($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification;
|
||||||
|
}
|
|
@ -1,165 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/notification-matrix
|
#
|
||||||
# Copyright (c) 2013-2023 Michael Gisbers <michael@gisbers.de>
|
# dummy for migration
|
||||||
# Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global FlushMatrixQueue;
|
|
||||||
:global NotificationFunctions;
|
|
||||||
:global SendMatrix;
|
|
||||||
:global SendMatrix2;
|
|
||||||
|
|
||||||
# flush Matrix queue
|
|
||||||
:set FlushMatrixQueue do={
|
|
||||||
:global MatrixQueue;
|
|
||||||
|
|
||||||
:global IsFullyConnected;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:if ([ $IsFullyConnected ] = false) do={
|
|
||||||
$LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local AllDone true;
|
|
||||||
:local QueueLen [ :len $MatrixQueue ];
|
|
||||||
|
|
||||||
:if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Id,Message in=$MatrixQueue do={
|
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
|
||||||
:do {
|
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
|
||||||
("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \
|
|
||||||
"/send/m.room.message?access_token=" . $Message->"accesstoken") \
|
|
||||||
http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \
|
|
||||||
"\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \
|
|
||||||
$Message->"formatted" . "\" }") as-value;
|
|
||||||
:set ($MatrixQueue->$Id);
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false;
|
|
||||||
:set AllDone false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={
|
|
||||||
/system/scheduler/remove [ find where name=$0 ];
|
|
||||||
:set MatrixQueue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via Matrix - expects one array argument
|
|
||||||
:set ($NotificationFunctions->"matrix") do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
:global IdentityExtra;
|
|
||||||
:global MatrixAccessToken;
|
|
||||||
:global MatrixAccessTokenOverride;
|
|
||||||
:global MatrixHomeServer;
|
|
||||||
:global MatrixHomeServerOverride;
|
|
||||||
:global MatrixQueue;
|
|
||||||
:global MatrixRoom;
|
|
||||||
:global MatrixRoomOverride;
|
|
||||||
|
|
||||||
:global EitherOr;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
|
|
||||||
:local PrepareText do={
|
|
||||||
:local Input [ :tostr $1 ];
|
|
||||||
|
|
||||||
:if ([ :len $Input ] = 0) do={
|
|
||||||
:return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Return "";
|
|
||||||
:local Chars {
|
|
||||||
"plain"={ "\\"; "\""; "\n" };
|
|
||||||
"format"={ "\\"; "\""; "\n"; "&"; "<"; ">" };
|
|
||||||
}
|
|
||||||
:local Subs {
|
|
||||||
"plain"={ "\\\\"; "\\\""; "\\n" };
|
|
||||||
"format"={ "\\\\"; """; "<br/>"; "&"; "<"; ">" };
|
|
||||||
}
|
|
||||||
|
|
||||||
:for I from=0 to=([ :len $Input ] - 1) do={
|
|
||||||
:local Char [ :pick $Input $I ];
|
|
||||||
:local Replace [ :find ($Chars->$2) $Char ];
|
|
||||||
|
|
||||||
:if ([ :typeof $Replace ] = "num") do={
|
|
||||||
:set Char ($Subs->$2->$Replace);
|
|
||||||
}
|
|
||||||
:set Return ($Return . $Char);
|
|
||||||
}
|
|
||||||
|
|
||||||
:return $Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ];
|
|
||||||
:local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ];
|
|
||||||
:local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ];
|
|
||||||
|
|
||||||
:if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \
|
|
||||||
($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ];
|
|
||||||
:local Formatted ("<h2>" . [ $PrepareText ("[" . $IdentityExtra . $Identity . "] " . \
|
|
||||||
($Notification->"subject")) "format" ] . "</h2>" . "<pre><code>" . \
|
|
||||||
[ $PrepareText ($Notification->"message") "format" ] . "</code></pre>");
|
|
||||||
:if ([ :len ($Notification->"link") ] > 0) do={
|
|
||||||
:set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \
|
|
||||||
[ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]);
|
|
||||||
:set Formatted ($Formatted . "<br/>" . [ $SymbolForNotification "link" ] . \
|
|
||||||
"<a href=\\\"" . [ $PrepareText ($Notification->"link") "format" ] . "\\\">" . \
|
|
||||||
[ $PrepareText ($Notification->"link") "format" ] . "</a>");
|
|
||||||
}
|
|
||||||
|
|
||||||
:do {
|
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
|
||||||
("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \
|
|
||||||
"/send/m.room.message?access_token=" . $AccessToken) \
|
|
||||||
http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \
|
|
||||||
"\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \
|
|
||||||
$Formatted . "\" }") as-value;
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false;
|
|
||||||
|
|
||||||
:if ([ :typeof $MatrixQueue ] = "nothing") do={
|
|
||||||
:set MatrixQueue ({});
|
|
||||||
}
|
|
||||||
:local Text ([ $SymbolForNotification "alarm-clock" ] . \
|
|
||||||
"This message was queued since " . [ /system/clock/get date ] . \
|
|
||||||
" " . [ /system/clock/get time ] . " and may be obsolete.");
|
|
||||||
:set Plain ($Plain . "\\n" . $Text);
|
|
||||||
:set Formatted ($Formatted . "<br/>" . $Text);
|
|
||||||
:set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \
|
|
||||||
accesstoken=$AccessToken; homeserver=$HomeServer; \
|
|
||||||
plain=$Plain; formatted=$Formatted };
|
|
||||||
:if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={
|
|
||||||
/system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \
|
|
||||||
on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via Matrix - expects at least two string arguments
|
|
||||||
:set SendMatrix do={
|
|
||||||
:global SendMatrix2;
|
|
||||||
|
|
||||||
$SendMatrix2 ({ subject=$1; message=$2; link=$3 });
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via Matrix - expects one array argument
|
|
||||||
:set SendMatrix2 do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global NotificationFunctions;
|
|
||||||
|
|
||||||
($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification;
|
|
||||||
}
|
|
||||||
|
|
165
mod/notification-matrix.rsc
Normal file
165
mod/notification-matrix.rsc
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/notification-matrix
|
||||||
|
# Copyright (c) 2013-2023 Michael Gisbers <michael@gisbers.de>
|
||||||
|
# Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global FlushMatrixQueue;
|
||||||
|
:global NotificationFunctions;
|
||||||
|
:global SendMatrix;
|
||||||
|
:global SendMatrix2;
|
||||||
|
|
||||||
|
# flush Matrix queue
|
||||||
|
:set FlushMatrixQueue do={
|
||||||
|
:global MatrixQueue;
|
||||||
|
|
||||||
|
:global IsFullyConnected;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:if ([ $IsFullyConnected ] = false) do={
|
||||||
|
$LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local AllDone true;
|
||||||
|
:local QueueLen [ :len $MatrixQueue ];
|
||||||
|
|
||||||
|
:if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Id,Message in=$MatrixQueue do={
|
||||||
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
|
:do {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
|
("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \
|
||||||
|
"/send/m.room.message?access_token=" . $Message->"accesstoken") \
|
||||||
|
http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Message->"plain" . "\"," . \
|
||||||
|
"\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \
|
||||||
|
$Message->"formatted" . "\" }") as-value;
|
||||||
|
:set ($MatrixQueue->$Id);
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false;
|
||||||
|
:set AllDone false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={
|
||||||
|
/system/scheduler/remove [ find where name=$0 ];
|
||||||
|
:set MatrixQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via Matrix - expects one array argument
|
||||||
|
:set ($NotificationFunctions->"matrix") do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global IdentityExtra;
|
||||||
|
:global MatrixAccessToken;
|
||||||
|
:global MatrixAccessTokenOverride;
|
||||||
|
:global MatrixHomeServer;
|
||||||
|
:global MatrixHomeServerOverride;
|
||||||
|
:global MatrixQueue;
|
||||||
|
:global MatrixRoom;
|
||||||
|
:global MatrixRoomOverride;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
:local PrepareText do={
|
||||||
|
:local Input [ :tostr $1 ];
|
||||||
|
|
||||||
|
:if ([ :len $Input ] = 0) do={
|
||||||
|
:return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Return "";
|
||||||
|
:local Chars {
|
||||||
|
"plain"={ "\\"; "\""; "\n" };
|
||||||
|
"format"={ "\\"; "\""; "\n"; "&"; "<"; ">" };
|
||||||
|
}
|
||||||
|
:local Subs {
|
||||||
|
"plain"={ "\\\\"; "\\\""; "\\n" };
|
||||||
|
"format"={ "\\\\"; """; "<br/>"; "&"; "<"; ">" };
|
||||||
|
}
|
||||||
|
|
||||||
|
:for I from=0 to=([ :len $Input ] - 1) do={
|
||||||
|
:local Char [ :pick $Input $I ];
|
||||||
|
:local Replace [ :find ($Chars->$2) $Char ];
|
||||||
|
|
||||||
|
:if ([ :typeof $Replace ] = "num") do={
|
||||||
|
:set Char ($Subs->$2->$Replace);
|
||||||
|
}
|
||||||
|
:set Return ($Return . $Char);
|
||||||
|
}
|
||||||
|
|
||||||
|
:return $Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ];
|
||||||
|
:local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ];
|
||||||
|
:local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ];
|
||||||
|
|
||||||
|
:if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \
|
||||||
|
($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ];
|
||||||
|
:local Formatted ("<h2>" . [ $PrepareText ("[" . $IdentityExtra . $Identity . "] " . \
|
||||||
|
($Notification->"subject")) "format" ] . "</h2>" . "<pre><code>" . \
|
||||||
|
[ $PrepareText ($Notification->"message") "format" ] . "</code></pre>");
|
||||||
|
:if ([ :len ($Notification->"link") ] > 0) do={
|
||||||
|
:set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \
|
||||||
|
[ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]);
|
||||||
|
:set Formatted ($Formatted . "<br/>" . [ $SymbolForNotification "link" ] . \
|
||||||
|
"<a href=\\\"" . [ $PrepareText ($Notification->"link") "format" ] . "\\\">" . \
|
||||||
|
[ $PrepareText ($Notification->"link") "format" ] . "</a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
:do {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
|
("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \
|
||||||
|
"/send/m.room.message?access_token=" . $AccessToken) \
|
||||||
|
http-data=("{ \"msgtype\": \"m.text\", \"body\": \"" . $Plain . "\"," . \
|
||||||
|
"\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \
|
||||||
|
$Formatted . "\" }") as-value;
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false;
|
||||||
|
|
||||||
|
:if ([ :typeof $MatrixQueue ] = "nothing") do={
|
||||||
|
:set MatrixQueue ({});
|
||||||
|
}
|
||||||
|
:local Text ([ $SymbolForNotification "alarm-clock" ] . \
|
||||||
|
"This message was queued since " . [ /system/clock/get date ] . \
|
||||||
|
" " . [ /system/clock/get time ] . " and may be obsolete.");
|
||||||
|
:set Plain ($Plain . "\\n" . $Text);
|
||||||
|
:set Formatted ($Formatted . "<br/>" . $Text);
|
||||||
|
:set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \
|
||||||
|
accesstoken=$AccessToken; homeserver=$HomeServer; \
|
||||||
|
plain=$Plain; formatted=$Formatted };
|
||||||
|
:if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={
|
||||||
|
/system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \
|
||||||
|
on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via Matrix - expects at least two string arguments
|
||||||
|
:set SendMatrix do={
|
||||||
|
:global SendMatrix2;
|
||||||
|
|
||||||
|
$SendMatrix2 ({ subject=$1; message=$2; link=$3 });
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via Matrix - expects one array argument
|
||||||
|
:set SendMatrix2 do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global NotificationFunctions;
|
||||||
|
|
||||||
|
($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification;
|
||||||
|
}
|
|
@ -1,176 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/notification-telegram
|
#
|
||||||
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global FlushTelegramQueue;
|
|
||||||
:global NotificationFunctions;
|
|
||||||
:global SendTelegram;
|
|
||||||
:global SendTelegram2;
|
|
||||||
|
|
||||||
# flush telegram queue
|
|
||||||
:set FlushTelegramQueue do={
|
|
||||||
:global TelegramQueue;
|
|
||||||
|
|
||||||
:global IsFullyConnected;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:if ([ $IsFullyConnected ] = false) do={
|
|
||||||
$LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false;
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local AllDone true;
|
|
||||||
:local QueueLen [ :len $TelegramQueue ];
|
|
||||||
|
|
||||||
:if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:foreach Id,Message in=$TelegramQueue do={
|
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
|
||||||
:do {
|
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none 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=" . ($Notification->"replyto") . \
|
|
||||||
"&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \
|
|
||||||
"&text=" . ($Message->"text")) as-value;
|
|
||||||
:set ($TelegramQueue->$Id);
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false;
|
|
||||||
:set AllDone false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={
|
|
||||||
/system/scheduler/remove [ find where name=$0 ];
|
|
||||||
:set TelegramQueue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via telegram - expects one array argument
|
|
||||||
:set ($NotificationFunctions->"telegram") do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global Identity;
|
|
||||||
:global IdentityExtra;
|
|
||||||
:global TelegramChatId;
|
|
||||||
:global TelegramChatIdOverride;
|
|
||||||
:global TelegramFixedWidthFont;
|
|
||||||
:global TelegramQueue;
|
|
||||||
:global TelegramTokenId;
|
|
||||||
:global TelegramTokenIdOverride;
|
|
||||||
|
|
||||||
:global CertificateAvailable;
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global EitherOr;
|
|
||||||
:global IfThenElse;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global SymbolForNotification;
|
|
||||||
:global UrlEncode;
|
|
||||||
|
|
||||||
:local EscapeMD do={
|
|
||||||
:global TelegramFixedWidthFont;
|
|
||||||
|
|
||||||
:global CharacterReplace;
|
|
||||||
:global IfThenElse;
|
|
||||||
|
|
||||||
:if ($TelegramFixedWidthFont != true) do={
|
|
||||||
:return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Return $1;
|
|
||||||
:local Chars {
|
|
||||||
"body"={ "\\"; "`" };
|
|
||||||
"plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">";
|
|
||||||
"#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" };
|
|
||||||
}
|
|
||||||
:foreach Char in=($Chars->$2) do={
|
|
||||||
:set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ];
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($2 = "body") do={
|
|
||||||
:return ("```\n" . $Return . "\n```");
|
|
||||||
}
|
|
||||||
|
|
||||||
:return $Return;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local ChatId [ $EitherOr ($Notification->"chatid") \
|
|
||||||
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
|
|
||||||
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
|
|
||||||
|
|
||||||
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Truncated false;
|
|
||||||
:local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \
|
|
||||||
($Notification->"subject")) "plain" ] . "__*\n\n");
|
|
||||||
:local LenSubject [ :len $Text ];
|
|
||||||
:local LenMessage [ :len ($Notification->"message") ];
|
|
||||||
:local LenLink [ :len ($Notification->"link") ];
|
|
||||||
:local LenSum ($LenSubject + $LenMessage + $LenLink);
|
|
||||||
:if ($LenSum > 3968) do={
|
|
||||||
:set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]);
|
|
||||||
:set Truncated true;
|
|
||||||
} else={
|
|
||||||
:set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]);
|
|
||||||
}
|
|
||||||
:if ($LenLink > 0) do={
|
|
||||||
:set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]);
|
|
||||||
}
|
|
||||||
:if ($Truncated = true) do={
|
|
||||||
:set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \
|
|
||||||
[ $EscapeMD ("The message was too long and has been truncated, cut off " . \
|
|
||||||
(($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]);
|
|
||||||
}
|
|
||||||
:set Text [ $UrlEncode $Text ];
|
|
||||||
:local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ];
|
|
||||||
|
|
||||||
:do {
|
|
||||||
:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Downloading required certificate failed.") true;
|
|
||||||
}
|
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none 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=" . $ParseMode . "&text=" . $Text) as-value;
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false;
|
|
||||||
|
|
||||||
:if ([ :typeof $TelegramQueue ] = "nothing") do={
|
|
||||||
:set TelegramQueue ({});
|
|
||||||
}
|
|
||||||
:set Text ($Text . [ $UrlEncode ("\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;
|
|
||||||
parsemode=$ParseMode; text=$Text; silent=($Notification->"silent");
|
|
||||||
replyto=($Notification->"replyto") };
|
|
||||||
: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;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via telegram - expects at least two string arguments
|
|
||||||
:set SendTelegram do={
|
|
||||||
:global SendTelegram2;
|
|
||||||
|
|
||||||
$SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 });
|
|
||||||
}
|
|
||||||
|
|
||||||
# send notification via telegram - expects one array argument
|
|
||||||
:set SendTelegram2 do={
|
|
||||||
:local Notification $1;
|
|
||||||
|
|
||||||
:global NotificationFunctions;
|
|
||||||
|
|
||||||
($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification;
|
|
||||||
}
|
|
||||||
|
|
176
mod/notification-telegram.rsc
Normal file
176
mod/notification-telegram.rsc
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/notification-telegram
|
||||||
|
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global FlushTelegramQueue;
|
||||||
|
:global NotificationFunctions;
|
||||||
|
:global SendTelegram;
|
||||||
|
:global SendTelegram2;
|
||||||
|
|
||||||
|
# flush telegram queue
|
||||||
|
:set FlushTelegramQueue do={
|
||||||
|
:global TelegramQueue;
|
||||||
|
|
||||||
|
:global IsFullyConnected;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:if ([ $IsFullyConnected ] = false) do={
|
||||||
|
$LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local AllDone true;
|
||||||
|
:local QueueLen [ :len $TelegramQueue ];
|
||||||
|
|
||||||
|
:if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Id,Message in=$TelegramQueue do={
|
||||||
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
|
:do {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none 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=" . ($Notification->"replyto") . \
|
||||||
|
"&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \
|
||||||
|
"&text=" . ($Message->"text")) as-value;
|
||||||
|
:set ($TelegramQueue->$Id);
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false;
|
||||||
|
:set AllDone false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={
|
||||||
|
/system/scheduler/remove [ find where name=$0 ];
|
||||||
|
:set TelegramQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via telegram - expects one array argument
|
||||||
|
:set ($NotificationFunctions->"telegram") do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global IdentityExtra;
|
||||||
|
:global TelegramChatId;
|
||||||
|
:global TelegramChatIdOverride;
|
||||||
|
:global TelegramFixedWidthFont;
|
||||||
|
:global TelegramQueue;
|
||||||
|
:global TelegramTokenId;
|
||||||
|
:global TelegramTokenIdOverride;
|
||||||
|
|
||||||
|
:global CertificateAvailable;
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global EitherOr;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global UrlEncode;
|
||||||
|
|
||||||
|
:local EscapeMD do={
|
||||||
|
:global TelegramFixedWidthFont;
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
|
:global IfThenElse;
|
||||||
|
|
||||||
|
:if ($TelegramFixedWidthFont != true) do={
|
||||||
|
:return ($1 . [ $IfThenElse ($2 = "body") ("\n") "" ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Return $1;
|
||||||
|
:local Chars {
|
||||||
|
"body"={ "\\"; "`" };
|
||||||
|
"plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">";
|
||||||
|
"#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" };
|
||||||
|
}
|
||||||
|
:foreach Char in=($Chars->$2) do={
|
||||||
|
:set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ];
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($2 = "body") do={
|
||||||
|
:return ("```\n" . $Return . "\n```");
|
||||||
|
}
|
||||||
|
|
||||||
|
:return $Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local ChatId [ $EitherOr ($Notification->"chatid") \
|
||||||
|
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
|
||||||
|
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
|
||||||
|
|
||||||
|
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Truncated false;
|
||||||
|
:local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \
|
||||||
|
($Notification->"subject")) "plain" ] . "__*\n\n");
|
||||||
|
:local LenSubject [ :len $Text ];
|
||||||
|
:local LenMessage [ :len ($Notification->"message") ];
|
||||||
|
:local LenLink [ :len ($Notification->"link") ];
|
||||||
|
:local LenSum ($LenSubject + $LenMessage + $LenLink);
|
||||||
|
:if ($LenSum > 3968) do={
|
||||||
|
:set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]);
|
||||||
|
:set Truncated true;
|
||||||
|
} else={
|
||||||
|
:set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]);
|
||||||
|
}
|
||||||
|
:if ($LenLink > 0) do={
|
||||||
|
:set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD ($Notification->"link") "plain" ]);
|
||||||
|
}
|
||||||
|
:if ($Truncated = true) do={
|
||||||
|
:set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \
|
||||||
|
[ $EscapeMD ("The message was too long and has been truncated, cut off " . \
|
||||||
|
(($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]);
|
||||||
|
}
|
||||||
|
:set Text [ $UrlEncode $Text ];
|
||||||
|
:local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ];
|
||||||
|
|
||||||
|
:do {
|
||||||
|
:if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Downloading required certificate failed.") true;
|
||||||
|
}
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none 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=" . $ParseMode . "&text=" . $Text) as-value;
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false;
|
||||||
|
|
||||||
|
:if ([ :typeof $TelegramQueue ] = "nothing") do={
|
||||||
|
:set TelegramQueue ({});
|
||||||
|
}
|
||||||
|
:set Text ($Text . [ $UrlEncode ("\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;
|
||||||
|
parsemode=$ParseMode; text=$Text; silent=($Notification->"silent");
|
||||||
|
replyto=($Notification->"replyto") };
|
||||||
|
: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;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via telegram - expects at least two string arguments
|
||||||
|
:set SendTelegram do={
|
||||||
|
:global SendTelegram2;
|
||||||
|
|
||||||
|
$SendTelegram2 ({ subject=$1; message=$2; link=$3; silent=$4 });
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via telegram - expects one array argument
|
||||||
|
:set SendTelegram2 do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global NotificationFunctions;
|
||||||
|
|
||||||
|
($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification;
|
||||||
|
}
|
|
@ -1,46 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mod/scriptrunonece
|
#
|
||||||
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
|
|
||||||
:global ScriptRunOnce;
|
|
||||||
|
|
||||||
# fetch and run script(s) once
|
|
||||||
:set ScriptRunOnce do={
|
|
||||||
:local Scripts [ :toarray $1 ];
|
|
||||||
|
|
||||||
:global ScriptRunOnceBaseUrl;
|
|
||||||
:global ScriptRunOnceUrlSuffix;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ValidateSyntax;
|
|
||||||
|
|
||||||
:foreach Script in=$Scripts do={
|
|
||||||
:if (!($Script ~ "^(ftp|https\?|sftp)://")) do={
|
|
||||||
:if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true;
|
|
||||||
}
|
|
||||||
:set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Source;
|
|
||||||
:do {
|
|
||||||
:set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data");
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $Source ] > 0) do={
|
|
||||||
:if ([ $ValidateSyntax $Source ] = true) do={
|
|
||||||
:do {
|
|
||||||
$LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false;
|
|
||||||
[ :parse $Source ];
|
|
||||||
} on-error={
|
|
||||||
$LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
46
mod/scriptrunonce.rsc
Normal file
46
mod/scriptrunonce.rsc
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/scriptrunonece
|
||||||
|
# Copyright (c) 2020-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
|
||||||
|
:global ScriptRunOnce;
|
||||||
|
|
||||||
|
# fetch and run script(s) once
|
||||||
|
:set ScriptRunOnce do={
|
||||||
|
:local Scripts [ :toarray $1 ];
|
||||||
|
|
||||||
|
:global ScriptRunOnceBaseUrl;
|
||||||
|
:global ScriptRunOnceUrlSuffix;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ValidateSyntax;
|
||||||
|
|
||||||
|
:foreach Script in=$Scripts do={
|
||||||
|
:if (!($Script ~ "^(ftp|https\?|sftp)://")) do={
|
||||||
|
:if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true;
|
||||||
|
}
|
||||||
|
: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={
|
||||||
|
$LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $Source ] > 0) do={
|
||||||
|
:if ([ $ValidateSyntax $Source ] = true) do={
|
||||||
|
:do {
|
||||||
|
$LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false;
|
||||||
|
[ :parse $Source ];
|
||||||
|
} on-error={
|
||||||
|
$LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
mode-button
75
mode-button
|
@ -1,76 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: mode-button
|
|
||||||
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# act on multiple mode and reset button presses
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md
|
|
||||||
|
|
||||||
:local 0 "mode-button";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global ModeButton;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
|
|
||||||
:set ($ModeButton->"count") ($ModeButton->"count" + 1);
|
|
||||||
|
|
||||||
:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ];
|
|
||||||
|
|
||||||
:if ([ :len $Scheduler ] = 0) do={
|
|
||||||
$LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false;
|
|
||||||
:global ModeButtonScheduler do={
|
|
||||||
:global ModeButton;
|
|
||||||
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ModeButtonScheduler;
|
|
||||||
:global ValidateSyntax;
|
|
||||||
|
|
||||||
:local LEDInvert do={
|
|
||||||
:global ModeButtonLED;
|
|
||||||
|
|
||||||
:global IfThenElse;
|
|
||||||
|
|
||||||
:local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ];
|
|
||||||
:if ([ :len $LED ] = 0) do={
|
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
/system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Count ($ModeButton->"count");
|
|
||||||
:local Code ($ModeButton->[ :tostr $Count ]);
|
|
||||||
|
|
||||||
:set ($ModeButton->"count") 0;
|
|
||||||
:set ModeButtonScheduler;
|
|
||||||
/system/scheduler/remove ModeButtonScheduler;
|
|
||||||
|
|
||||||
:if ([ :len $Code ] > 0) do={
|
|
||||||
:if ([ $ValidateSyntax $Code ] = true) do={
|
|
||||||
$LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false;
|
|
||||||
|
|
||||||
:for I from=1 to=$Count do={
|
|
||||||
$LEDInvert;
|
|
||||||
:if ([ /system/routerboard/settings/get silent-boot ] = false) do={
|
|
||||||
:beep length=200ms;
|
|
||||||
}
|
|
||||||
:delay 200ms;
|
|
||||||
$LEDInvert;
|
|
||||||
:delay 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
[ :parse $Code ];
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/system/scheduler/add name="ModeButtonScheduler" \
|
|
||||||
on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s;
|
|
||||||
} else={
|
|
||||||
$LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false;
|
|
||||||
/system/scheduler/set $Scheduler start-time=[ /system/clock/get time ];
|
|
||||||
}
|
|
||||||
|
|
76
mode-button.rsc
Normal file
76
mode-button.rsc
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mode-button
|
||||||
|
# Copyright (c) 2018-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# act on multiple mode and reset button presses
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md
|
||||||
|
|
||||||
|
:local 0 "mode-button";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global ModeButton;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
|
||||||
|
:set ($ModeButton->"count") ($ModeButton->"count" + 1);
|
||||||
|
|
||||||
|
:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ];
|
||||||
|
|
||||||
|
:if ([ :len $Scheduler ] = 0) do={
|
||||||
|
$LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false;
|
||||||
|
:global ModeButtonScheduler do={
|
||||||
|
:global ModeButton;
|
||||||
|
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ModeButtonScheduler;
|
||||||
|
:global ValidateSyntax;
|
||||||
|
|
||||||
|
:local LEDInvert do={
|
||||||
|
:global ModeButtonLED;
|
||||||
|
|
||||||
|
:global IfThenElse;
|
||||||
|
|
||||||
|
:local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ];
|
||||||
|
:if ([ :len $LED ] = 0) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
/system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Count ($ModeButton->"count");
|
||||||
|
:local Code ($ModeButton->[ :tostr $Count ]);
|
||||||
|
|
||||||
|
:set ($ModeButton->"count") 0;
|
||||||
|
:set ModeButtonScheduler;
|
||||||
|
/system/scheduler/remove ModeButtonScheduler;
|
||||||
|
|
||||||
|
:if ([ :len $Code ] > 0) do={
|
||||||
|
:if ([ $ValidateSyntax $Code ] = true) do={
|
||||||
|
$LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false;
|
||||||
|
|
||||||
|
:for I from=1 to=$Count do={
|
||||||
|
$LEDInvert;
|
||||||
|
:if ([ /system/routerboard/settings/get silent-boot ] = false) do={
|
||||||
|
:beep length=200ms;
|
||||||
|
}
|
||||||
|
:delay 200ms;
|
||||||
|
$LEDInvert;
|
||||||
|
:delay 200ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ :parse $Code ];
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/system/scheduler/add name="ModeButtonScheduler" \
|
||||||
|
on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s;
|
||||||
|
} else={
|
||||||
|
$LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false;
|
||||||
|
/system/scheduler/set $Scheduler start-time=[ /system/clock/get time ];
|
||||||
|
}
|
93
netwatch-dns
93
netwatch-dns
|
@ -1,94 +1,3 @@
|
||||||
#!rsc by RouterOS
|
#!rsc by RouterOS
|
||||||
# RouterOS script: netwatch-dns
|
|
||||||
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
|
||||||
#
|
#
|
||||||
# monitor and manage dns/doh with netwatch
|
# dummy for migration
|
||||||
# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md
|
|
||||||
|
|
||||||
:local 0 "netwatch-dns";
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:global CertificateAvailable;
|
|
||||||
:global EitherOr;
|
|
||||||
:global LogPrintExit2;
|
|
||||||
:global ParseKeyValueStore;
|
|
||||||
:global ScriptLock;
|
|
||||||
|
|
||||||
$ScriptLock $0;
|
|
||||||
|
|
||||||
:if ([ /system/resource/get uptime ] < 5m) do={
|
|
||||||
$LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local DnsServers ({});
|
|
||||||
:local DnsFallback ({});
|
|
||||||
:local DnsCurrent [ /ip/dns/get servers ];
|
|
||||||
|
|
||||||
:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={
|
|
||||||
:local HostVal [ /tool/netwatch/get $Host ];
|
|
||||||
:local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ];
|
|
||||||
|
|
||||||
:if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={
|
|
||||||
:if ($HostInfo->"dns" = true) do={
|
|
||||||
:set DnsServers ($DnsServers, $HostVal->"host");
|
|
||||||
}
|
|
||||||
:if ($HostInfo->"dns-fallback" = true) do={
|
|
||||||
:set DnsFallback ($DnsFallback, $HostVal->"host");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ([ :len $DnsServers ] > 0) do={
|
|
||||||
:if ($DnsServers != $DnsCurrent) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false;
|
|
||||||
/ip/dns/set servers=$DnsServers;
|
|
||||||
/ip/dns/cache/flush;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
:if ([ :len $DnsFallback ] > 0) do={
|
|
||||||
:if ($DnsFallback != $DnsCurrent) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \
|
|
||||||
[ :tostr $DnsFallback ]) false;
|
|
||||||
/ip/dns/set servers=$DnsFallback;
|
|
||||||
/ip/dns/cache/flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local DohServer "";
|
|
||||||
:local DohCurrent [ /ip/dns/get use-doh-server ];
|
|
||||||
:local DohCert "";
|
|
||||||
|
|
||||||
:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={
|
|
||||||
:local HostVal [ /tool/netwatch/get $Host ];
|
|
||||||
:local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ];
|
|
||||||
|
|
||||||
:if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \
|
|
||||||
$HostInfo->"disabled" != true && $DohServer = "") do={
|
|
||||||
:set DohServer [ $EitherOr ($HostInfo->"doh-url") \
|
|
||||||
("https://" . $HostVal->"host" . "/dns-query") ];
|
|
||||||
:set DohCert ($HostInfo->"doh-cert");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($DohServer != "") do={
|
|
||||||
:if ($DohServer != $DohCurrent) do={
|
|
||||||
$LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false;
|
|
||||||
:if ([ :len $DohCert ] > 0) do={
|
|
||||||
/ip/dns/set use-doh-server="";
|
|
||||||
:if ([ $CertificateAvailable $DohCert ] = false) do={
|
|
||||||
$LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/ip/dns/set use-doh-server=$DohServer;
|
|
||||||
/ip/dns/cache/flush;
|
|
||||||
}
|
|
||||||
} else={
|
|
||||||
:if ($DohCurrent != "") do={
|
|
||||||
$LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false;
|
|
||||||
/ip/dns/set use-doh-server="";
|
|
||||||
/ip/dns/cache/flush;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
94
netwatch-dns.rsc
Normal file
94
netwatch-dns.rsc
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: netwatch-dns
|
||||||
|
# Copyright (c) 2022-2023 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md
|
||||||
|
#
|
||||||
|
# monitor and manage dns/doh with netwatch
|
||||||
|
# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md
|
||||||
|
|
||||||
|
:local 0 "netwatch-dns";
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
|
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
||||||
|
:global CertificateAvailable;
|
||||||
|
:global EitherOr;
|
||||||
|
:global LogPrintExit2;
|
||||||
|
:global ParseKeyValueStore;
|
||||||
|
:global ScriptLock;
|
||||||
|
|
||||||
|
$ScriptLock $0;
|
||||||
|
|
||||||
|
:if ([ /system/resource/get uptime ] < 5m) do={
|
||||||
|
$LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local DnsServers ({});
|
||||||
|
:local DnsFallback ({});
|
||||||
|
:local DnsCurrent [ /ip/dns/get servers ];
|
||||||
|
|
||||||
|
:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={
|
||||||
|
:local HostVal [ /tool/netwatch/get $Host ];
|
||||||
|
:local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ];
|
||||||
|
|
||||||
|
:if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={
|
||||||
|
:if ($HostInfo->"dns" = true) do={
|
||||||
|
:set DnsServers ($DnsServers, $HostVal->"host");
|
||||||
|
}
|
||||||
|
:if ($HostInfo->"dns-fallback" = true) do={
|
||||||
|
:set DnsFallback ($DnsFallback, $HostVal->"host");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $DnsServers ] > 0) do={
|
||||||
|
:if ($DnsServers != $DnsCurrent) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false;
|
||||||
|
/ip/dns/set servers=$DnsServers;
|
||||||
|
/ip/dns/cache/flush;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:if ([ :len $DnsFallback ] > 0) do={
|
||||||
|
:if ($DnsFallback != $DnsCurrent) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \
|
||||||
|
[ :tostr $DnsFallback ]) false;
|
||||||
|
/ip/dns/set servers=$DnsFallback;
|
||||||
|
/ip/dns/cache/flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:local DohServer "";
|
||||||
|
:local DohCurrent [ /ip/dns/get use-doh-server ];
|
||||||
|
:local DohCert "";
|
||||||
|
|
||||||
|
:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={
|
||||||
|
:local HostVal [ /tool/netwatch/get $Host ];
|
||||||
|
:local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ];
|
||||||
|
|
||||||
|
:if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \
|
||||||
|
$HostInfo->"disabled" != true && $DohServer = "") do={
|
||||||
|
:set DohServer [ $EitherOr ($HostInfo->"doh-url") \
|
||||||
|
("https://" . $HostVal->"host" . "/dns-query") ];
|
||||||
|
:set DohCert ($HostInfo->"doh-cert");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($DohServer != "") do={
|
||||||
|
:if ($DohServer != $DohCurrent) do={
|
||||||
|
$LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false;
|
||||||
|
:if ([ :len $DohCert ] > 0) do={
|
||||||
|
/ip/dns/set use-doh-server="";
|
||||||
|
:if ([ $CertificateAvailable $DohCert ] = false) do={
|
||||||
|
$LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/ip/dns/set use-doh-server=$DohServer;
|
||||||
|
/ip/dns/cache/flush;
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:if ($DohCurrent != "") do={
|
||||||
|
$LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false;
|
||||||
|
/ip/dns/set use-doh-server="";
|
||||||
|
/ip/dns/cache/flush;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue