Compare commits
304 commits
change-134
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
89175e511f | ||
|
b068f86995 | ||
|
d46574b4fe | ||
|
c3010af4ed | ||
|
1307b8587e | ||
|
6415849850 | ||
|
95f8af6234 | ||
|
de2a90d841 | ||
|
e2d3f0f073 | ||
|
595b4aea9d | ||
|
0de6d006ae | ||
|
1f4bf9ee63 | ||
|
c3d3d61f92 | ||
|
6130c94cc1 | ||
|
15fd522d3d | ||
|
5b15c82bb1 | ||
|
30b80e903d | ||
|
80aed200fd | ||
|
2d81984aed | ||
|
e3284ca770 | ||
|
daee05dbd7 | ||
|
43bac7c33c | ||
|
a2f837be59 | ||
|
8353a8547f | ||
|
cb984a5e52 | ||
|
0e00a228d6 | ||
|
e08bb2192d | ||
|
fb8e616846 | ||
|
d993495e44 | ||
|
1e4f168735 | ||
|
b70e6e7984 | ||
|
4bc3bf40e6 | ||
|
d69b399572 | ||
|
bf684a7197 | ||
|
d59c4aee26 | ||
|
3d3b270748 | ||
|
6a49c483b6 | ||
|
c50acd697a | ||
|
4bd7d44cd2 | ||
|
86ad41f6b6 | ||
|
64fe923c5a | ||
|
f1396b83aa | ||
|
1b5dd1e1d3 | ||
|
e78c71948d | ||
|
ce129ee441 | ||
|
2a95687477 | ||
|
74dc809b98 | ||
|
ff218e4ce5 | ||
|
bd3cc3bbd4 | ||
|
36f155ce62 | ||
|
187735f35f | ||
|
3521995dbc | ||
|
1f4290f4be | ||
|
205bcce6f9 | ||
|
10ac816348 | ||
|
f22d46da96 | ||
|
d0adf9974e | ||
|
fefe59751f | ||
|
a523f97938 | ||
|
c757064eb9 | ||
|
9cd4ed08a4 | ||
|
9ae21c00bd | ||
|
314e68e4cd | ||
|
e01873301f | ||
|
3f092d3477 | ||
|
2a7fd7ea53 | ||
|
5badafe109 | ||
|
c1e6348bb9 | ||
|
d5f9ecebfb | ||
|
5c599beae1 | ||
|
8b1b73c936 | ||
|
f5c4378676 | ||
|
12926b7c42 | ||
|
2317013121 | ||
|
86a8919ed2 | ||
|
09f9826760 | ||
|
7a1fef78a2 | ||
|
a6b36dde7b | ||
|
5b89f3e425 | ||
|
a9e7bb0a05 | ||
|
b807fc9e90 | ||
|
142b0760b0 | ||
|
79f681b801 | ||
|
1925d2847c | ||
|
187aeba78b | ||
|
dc2296d500 | ||
|
c3fce37066 | ||
|
6691e2e765 | ||
|
01f3cb91e7 | ||
|
9085780562 | ||
|
f095b581e7 | ||
|
661aad522b | ||
|
4561b17dbf | ||
|
39295b4954 | ||
|
0f58cecc0f | ||
|
f2dbb9eff3 | ||
|
b4d80d3b17 | ||
|
9b5419b939 | ||
|
15248ffd39 | ||
|
6270ac45d8 | ||
|
194698f53f | ||
|
38ec392a5f | ||
|
aaecd1b457 | ||
|
5b40380cd2 | ||
|
2d39dbdf7c | ||
|
bc1c238158 | ||
|
160effd91b | ||
|
10bd9a1cb5 | ||
|
59f9a1187f | ||
|
ce29fcf49e | ||
|
6a9fced721 | ||
|
713e63da87 | ||
|
148892694f | ||
|
9e70bca30b | ||
|
a68763c4dd | ||
|
857993cf90 | ||
|
ad6ad5bfcc | ||
|
be0e9be1ba | ||
|
b19c448f78 | ||
|
2afe734bc3 | ||
|
6040f70b19 | ||
|
286ed96cc3 | ||
|
af40ae82ed | ||
|
87edd0bd29 | ||
|
59c66de690 | ||
|
5958851bd7 | ||
|
35bce7c5eb | ||
|
78463f469b | ||
|
f7ba78702f | ||
|
24ea16cf91 | ||
|
506acb748b | ||
|
e3a15cc6b8 | ||
|
0ef8888412 | ||
|
1936dcb563 | ||
|
d865deb8a8 | ||
|
7b624faaa1 | ||
|
4954a88695 | ||
|
9d845d40f0 | ||
|
4358dabb19 | ||
|
ef1a402c4e | ||
|
862830b341 | ||
|
ff812dd192 | ||
|
40b19a179d | ||
|
8cddc63767 | ||
|
446aa3d7ff | ||
|
12037ff6e6 | ||
|
9b558ff8a1 | ||
|
2374be9a21 | ||
|
27fc07e940 | ||
|
d5141f43e5 | ||
|
63606ad25c | ||
|
200167fa38 | ||
|
02986eb77a | ||
|
a6ab95ccef | ||
|
37a6d4cc43 | ||
|
d2af793683 | ||
|
829fce789b | ||
|
d57916fc26 | ||
|
fe3d9f8418 | ||
|
41b705aa5a | ||
|
60c5e84401 | ||
|
3ad8cafc7a | ||
|
83cf003f62 | ||
|
bcdb74f31d | ||
|
aae9b4d4e3 | ||
|
057bbb8481 | ||
|
3eec13b8b5 | ||
|
76778f0431 | ||
|
aeccd36f16 | ||
|
925e7f869e | ||
|
9a5a2aec4f | ||
|
4b92181f2e | ||
|
c720eadd2c | ||
|
4d1349125d | ||
|
0df4170a2e | ||
|
a308d4269e | ||
|
2d41ad718d | ||
|
a556f4c398 | ||
|
ff03f49724 | ||
|
8418d58ff0 | ||
|
2712bcb44d | ||
|
69b2af4bd7 | ||
|
08d78224a0 | ||
|
8f1ac6fa17 | ||
|
96cbb32a4f | ||
|
9b811e1ed2 | ||
|
b4188ab1a2 | ||
|
de5aab12ae | ||
|
33393798b1 | ||
|
9423d8019a | ||
|
bf1b3e3c5e | ||
|
64ec962bb6 | ||
|
7d4e4ec273 | ||
|
9acf9781cb | ||
|
c643069b3e | ||
|
da93138017 | ||
|
39ab19b272 | ||
|
1075b6b24e | ||
|
9ae733a167 | ||
|
143b8a8ddc | ||
|
d609da0041 | ||
|
0e93d8ca66 | ||
|
d99380443b | ||
|
8ed83a311d | ||
|
5dc6b712e1 | ||
|
55e07a8a42 | ||
|
7d8e9fda29 | ||
|
472dc9289d | ||
|
f5c33a9cfb | ||
|
b959f2d941 | ||
|
051a1d95e5 | ||
|
e44a5384b7 | ||
|
009516dbd4 | ||
|
54a3012e89 | ||
|
e0ba2c8282 | ||
|
0a9acab040 | ||
|
34c052c5f1 | ||
|
953daca8ac | ||
|
02a205b14e | ||
|
b9faeb86b9 | ||
|
41bf9677db | ||
|
90f61d3d75 | ||
|
ccfe1a781e | ||
|
154fb43800 | ||
|
fa83c76be1 | ||
|
07541a3cbc | ||
|
0717ebfbd5 | ||
|
507a520994 | ||
|
fe64918118 | ||
|
3822887ba2 | ||
|
c69b13c879 | ||
|
183b16d83c | ||
|
0eaefcdc72 | ||
|
2fa044972c | ||
|
3788a3e286 | ||
|
34eac64f33 | ||
|
4118f53aae | ||
|
b12f8a3974 | ||
|
a1437a4c83 | ||
|
8328400e87 | ||
|
158230070f | ||
|
405c329f39 | ||
|
b78df91b23 | ||
|
29bcd191ee | ||
|
d80f43a1c8 | ||
|
390e3653d7 | ||
|
75163f0d3c | ||
|
d4b5e1f5e7 | ||
|
c823ff87ed | ||
|
44fa91f5c4 | ||
|
e36613608c | ||
|
019e10e190 | ||
|
314ba5796d | ||
|
67e7b11aa7 | ||
|
27987a0d7c | ||
|
2cc47f56b9 | ||
|
b560ea4b7d | ||
|
cdfb086b49 | ||
|
3c30276e23 | ||
|
16c9ce437e | ||
|
6909514692 | ||
|
f8c3659f6a | ||
|
ce39b79f69 | ||
|
20bf609c44 | ||
|
b63e0fcb2f | ||
|
1555426687 | ||
|
97b99316b2 | ||
|
788400c458 | ||
|
eb59dd21ca | ||
|
79a4b369cb | ||
|
f0e6cbcfe1 | ||
|
d71ea804b0 | ||
|
e148df9e57 | ||
|
2f55bfaf00 | ||
|
ea6de35699 | ||
|
fb343c99e3 | ||
|
7be26a0712 | ||
|
6d718ec987 | ||
|
e341e1c30c | ||
|
b43b1b3955 | ||
|
1b46a5fd9b | ||
|
b13360e4b8 | ||
|
c9de6d8579 | ||
|
10374afc18 | ||
|
0c1d96f89d | ||
|
3ccaafd1b3 | ||
|
469f783a92 | ||
|
33c02e0609 | ||
|
6331505dbe | ||
|
0c4fb42616 | ||
|
f5189b8bd7 | ||
|
e2fe653035 | ||
|
b11be59b08 | ||
|
24de060904 | ||
|
14195c51ca | ||
|
e833dfcf25 | ||
|
512c54bd59 | ||
|
3d40b4419d | ||
|
a6d4e7e82c | ||
|
f6c2225f68 | ||
|
53b13b295a | ||
|
4eafcaa3ac | ||
|
c33eb41c9c | ||
|
78f9687558 |
3
.gitignore
vendored
|
@ -9,5 +9,8 @@
|
||||||
# html files (as generated from markdown)
|
# html files (as generated from markdown)
|
||||||
*.html
|
*.html
|
||||||
|
|
||||||
|
# checksums file as used by $ScriptInstallUpdate
|
||||||
|
checksums.json
|
||||||
|
|
||||||
# Mac OS X folder settings file
|
# Mac OS X folder settings file
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -13,7 +13,7 @@ Installing from branches
|
||||||
> ⚠️ **Warning**: Living on the edge? Great, read on!
|
> ⚠️ **Warning**: Living on the edge? Great, read on!
|
||||||
> If not: Please use the `main` branch and leave this page!
|
> If not: Please use the `main` branch and leave this page!
|
||||||
|
|
||||||
These scripts are developed in a [git](https://git-scm.com/) repository.
|
These scripts are developed in a [git ↗️](https://git-scm.com/) repository.
|
||||||
Development and experimental branches are used to provide early access
|
Development and experimental branches are used to provide early access
|
||||||
for specific changes. You can install scripts from these branches
|
for specific changes. You can install scripts from these branches
|
||||||
for testing.
|
for testing.
|
||||||
|
|
|
@ -21,7 +21,7 @@ first step of [installation](README.md#the-long-way-in-detail) is importing
|
||||||
the certificate.
|
the certificate.
|
||||||
|
|
||||||
The scripts can install additional certificates when required. This happens
|
The scripts can install additional certificates when required. This happens
|
||||||
from this repository if available, or from [mkcert.org](https://mkcert.org)
|
from this repository if available, or from [mkcert.org ↗️](https://mkcert.org)
|
||||||
as a fallback.
|
as a fallback.
|
||||||
|
|
||||||
Get the certificate's CommonName
|
Get the certificate's CommonName
|
||||||
|
@ -29,7 +29,7 @@ Get the certificate's CommonName
|
||||||
|
|
||||||
But how to determine what certificate may be required? Often easiest way
|
But how to determine what certificate may be required? Often easiest way
|
||||||
is to use a desktop browser to get that information. This demonstration uses
|
is to use a desktop browser to get that information. This demonstration uses
|
||||||
[Mozilla Firefox](https://www.mozilla.org/firefox/).
|
[Mozilla Firefox ↗️](https://www.mozilla.org/firefox/).
|
||||||
|
|
||||||
Let's assume we want to make sure the certificate for
|
Let's assume we want to make sure the certificate for
|
||||||
[git.eworm.de](https://git.eworm.de/) is available. Open that page in the
|
[git.eworm.de](https://git.eworm.de/) is available. Open that page in the
|
||||||
|
@ -74,6 +74,7 @@ See also
|
||||||
|
|
||||||
* [Download, import and update firewall address-lists](doc/fw-addr-lists.md)
|
* [Download, import and update firewall address-lists](doc/fw-addr-lists.md)
|
||||||
* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md)
|
* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md)
|
||||||
|
* [Send notifications via Gotify](doc/mod/notification-gotify.md)
|
||||||
* [Send notifications via Matrix](doc/mod/notification-matrix.md)
|
* [Send notifications via Matrix](doc/mod/notification-matrix.md)
|
||||||
* [Send notifications via Ntfy](doc/mod/notification-ntfy.md)
|
* [Send notifications via Ntfy](doc/mod/notification-ntfy.md)
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ for details!
|
||||||
* [Ben Harris](mailto:mail@bharr.is) (@bharrisau)
|
* [Ben Harris](mailto:mail@bharr.is) (@bharrisau)
|
||||||
* [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg)
|
* [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg)
|
||||||
* [Ignacio Serrano](mailto:ignic@ignic.com) (@ignic)
|
* [Ignacio Serrano](mailto:ignic@ignic.com) (@ignic)
|
||||||
|
* [Ilya Kulakov](mailto:kulakov.ilya@gmail.com) (@Kentzo)
|
||||||
|
* [Leonardo David Monteiro](mailto:leo@cub3.xyz) (@leosfsm)
|
||||||
* [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers)
|
* [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers)
|
||||||
* [Miquel Bonastre](mailto:mbonastre@yahoo.com) (@mbonastre)
|
* [Miquel Bonastre](mailto:mbonastre@yahoo.com) (@mbonastre)
|
||||||
* @netravnen
|
* @netravnen
|
||||||
|
@ -30,9 +32,10 @@ for details!
|
||||||
## Donations
|
## Donations
|
||||||
|
|
||||||
Add yourself to the list,
|
Add yourself to the list,
|
||||||
[donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)!
|
[donate with PayPal ↗️](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)!
|
||||||
|
|
||||||
* Abdul Mannan Abbasi
|
* Abdul Mannan Abbasi
|
||||||
|
* Alex Maier
|
||||||
* Andrea Ruffini Perico
|
* Andrea Ruffini Perico
|
||||||
* Andrew Cox
|
* Andrew Cox
|
||||||
* Christoph Boss (@Kampfwurst)
|
* Christoph Boss (@Kampfwurst)
|
||||||
|
|
16
DEBUG.md
|
@ -42,7 +42,21 @@ Other actions (`disk`, `email`, `remote` or `support`) can be used as
|
||||||
well. I do not recommend using `echo` - use [debug output](#debug-output)
|
well. I do not recommend using `echo` - use [debug output](#debug-output)
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
Disable or remote that setting to restore regular logging.
|
Disable or remove that setting to restore regular logging.
|
||||||
|
|
||||||
|
## Verbose output
|
||||||
|
|
||||||
|
Specific scripts can generate huge amount of output. These do use a function
|
||||||
|
`$LogPrintVerbose`, which is declared, but has no code, intentionally.
|
||||||
|
|
||||||
|
If you *really* want that output set the function to be the same as
|
||||||
|
`$LogPrint`:
|
||||||
|
|
||||||
|
:set LogPrintVerbose $LogPrint;
|
||||||
|
|
||||||
|
To revert that change just run:
|
||||||
|
|
||||||
|
:set LogPrintVerbose;
|
||||||
|
|
||||||
---
|
---
|
||||||
[⬅️ Go back to main README](README.md)
|
[⬅️ Go back to main README](README.md)
|
||||||
|
|
|
@ -10,30 +10,46 @@ Initial commands
|
||||||
|
|
||||||
[⬅️ Go back to main README](README.md)
|
[⬅️ Go back to main README](README.md)
|
||||||
|
|
||||||
> ⚠️ **Warning**: These command are inteneded for initial setup. If you are
|
> ⚠️ **Warning**: These commands are intended for initial setup. If you are
|
||||||
> not aware of the procedure please follow
|
> not aware of the procedure please follow
|
||||||
> [the long way in detail](README.md#the-long-way-in-detail).
|
> [the long way in detail](README.md#the-long-way-in-detail).
|
||||||
|
|
||||||
Run the complete base installation:
|
Run the complete base installation:
|
||||||
|
|
||||||
{
|
{
|
||||||
/tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem" as-value;
|
:local BaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/";
|
||||||
:delay 1s;
|
:local CertCommonName "ISRG Root X2";
|
||||||
/certificate/import file-name=isrg-root-x2.pem passphrase="";
|
:local CertFileName "ISRG-Root-X2.pem";
|
||||||
:if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={
|
:local CertFingerprint "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470";
|
||||||
:error "Something is wrong with your certificates!";
|
|
||||||
|
:if (!(([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \
|
||||||
|
[[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CertCommonName . "\" ] ]") ]] > 0)) do={
|
||||||
|
:put "Importing certificate...";
|
||||||
|
/tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value;
|
||||||
|
:delay 1s;
|
||||||
|
/certificate/import file-name=$CertFileName passphrase="";
|
||||||
|
:if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] != 1) do={
|
||||||
|
:error "Something is wrong with your certificates!";
|
||||||
|
};
|
||||||
|
:delay 1s;
|
||||||
};
|
};
|
||||||
:delay 1s;
|
:put "Renaming global-config-overlay, if exists...";
|
||||||
/system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ];
|
/system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ];
|
||||||
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={
|
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={
|
||||||
|
:put "Installing $Script...";
|
||||||
/system/script/remove [ find where name=$Script ];
|
/system/script/remove [ find where name=$Script ];
|
||||||
/system/script/add name=$Script owner=$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/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ($BaseUrl . $Script . ".rsc") output=user as-value]->"data");
|
||||||
};
|
};
|
||||||
|
:put "Loading configuration and functions...";
|
||||||
/system/script { run global-config; run global-functions; };
|
/system/script { run global-config; run global-functions; };
|
||||||
|
:put "Scheduling to load configuration and functions...";
|
||||||
/system/scheduler/remove [ find where name="global-scripts" ];
|
/system/scheduler/remove [ find where name="global-scripts" ];
|
||||||
/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; }";
|
||||||
:global CertificateNameByCN;
|
:if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] > 0) do={
|
||||||
$CertificateNameByCN "ISRG Root X2";
|
:put "Renaming certificate by its common-name...";
|
||||||
|
:global CertificateNameByCN;
|
||||||
|
$CertificateNameByCN $CertFingerprint;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Then continue setup with
|
Then continue setup with
|
||||||
|
|
7
Makefile
|
@ -9,7 +9,7 @@ WIFI = $(wildcard *.wifi.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)
|
||||||
|
|
||||||
all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML)
|
all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML) checksums.json
|
||||||
|
|
||||||
%.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' > $@
|
||||||
|
@ -32,5 +32,8 @@ all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML)
|
||||||
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
|
||||||
< $< > $@
|
< $< > $@
|
||||||
|
|
||||||
|
checksums.json: contrib/checksums.sh *.rsc */*.rsc
|
||||||
|
contrib/checksums.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(HTML)
|
rm -f $(HTML) checksums.json
|
||||||
|
|
157
README.md
|
@ -10,13 +10,14 @@ RouterOS Scripts
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
[RouterOS](https://mikrotik.com/software) is the operating system developed
|
[RouterOS ↗️](https://mikrotik.com/software) is the operating system developed
|
||||||
by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This
|
by [MikroTik ↗️](https://mikrotik.com/aboutus) for networking tasks. This
|
||||||
repository holds a number of [scripts](https://wiki.mikrotik.com/wiki/Manual:Scripting)
|
repository holds a number of [scripts ↗️](https://wiki.mikrotik.com/wiki/Manual:Scripting)
|
||||||
to manage RouterOS devices or extend their functionality.
|
to manage RouterOS devices or extend their functionality.
|
||||||
|
|
||||||
*Use at your own risk*, pay attention to
|
*Use at your own risk*, pay attention to
|
||||||
[license and warranty](#license-and-warranty)!
|
[license and warranty](#license-and-warranty), and
|
||||||
|
[disclaimer on external links](#disclaimer-on-external-links)!
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
@ -35,7 +36,7 @@ Specific scripts may require even newer RouterOS version.
|
||||||
> running RouterOS v6 switch to `routeros-v6` branch!
|
> running RouterOS v6 switch to `routeros-v6` branch!
|
||||||
|
|
||||||
Starting with RouterOS 7.17 the
|
Starting with RouterOS 7.17 the
|
||||||
[device-mode](https://help.mikrotik.com/docs/spaces/ROS/pages/93749258/Device-mode)
|
[device-mode ↗️](https://help.mikrotik.com/docs/spaces/ROS/pages/93749258/Device-mode)
|
||||||
has been extended to give more fine-grained control over what features are
|
has been extended to give more fine-grained control over what features are
|
||||||
available. You need to enable `scheduler` and `fetch` at least, specific
|
available. You need to enable `scheduler` and `fetch` at least, specific
|
||||||
scripts may require additional features.
|
scripts may require additional features.
|
||||||
|
@ -61,9 +62,9 @@ First time users should take the long way below.
|
||||||
### Live presentation
|
### Live presentation
|
||||||
|
|
||||||
Want to see it in action? I've had a presentation [Repository based
|
Want to see it in action? I've had a presentation [Repository based
|
||||||
RouterOS script distribution](https://www.youtube.com/watch?v=B9neG3oAhcY)
|
RouterOS script distribution ↗️](https://www.youtube.com/watch?v=B9neG3oAhcY)
|
||||||
including demonstation recorded live at [MUM Europe
|
including demonstation recorded live at [MUM Europe
|
||||||
2019](https://mum.mikrotik.com/2019/EU/) in Vienna.
|
2019 ↗️](https://mum.mikrotik.com/2019/EU/) in Vienna.
|
||||||
|
|
||||||
> ⚠️ **Warning**: Some details changed. So see the presentation, then follow
|
> ⚠️ **Warning**: Some details changed. So see the presentation, then follow
|
||||||
> the steps below for up-to-date commands.
|
> the steps below for up-to-date commands.
|
||||||
|
@ -71,7 +72,15 @@ including demonstation recorded live at [MUM Europe
|
||||||
### The long way in detail
|
### The long way in detail
|
||||||
|
|
||||||
The update script does server certificate verification, so first step is to
|
The update script does server certificate verification, so first step is to
|
||||||
download the certificates. If you intend to download the scripts from a
|
download the certificates.
|
||||||
|
|
||||||
|
> 💡️ **Hint**: RouterOS 7.19 comes with a builtin certificate store. You
|
||||||
|
> can skip the steps regarding certificate download and import and jump
|
||||||
|
> to [installation of scripts](#installation-of-scripts) if you set the
|
||||||
|
> trust for these builtin trust anchors:
|
||||||
|
> `/certificate/settings/set builtin-trust-anchors=trusted;`
|
||||||
|
|
||||||
|
If you intend to download the scripts from a
|
||||||
different location (for example from github.com) install the corresponding
|
different location (for example from github.com) install the corresponding
|
||||||
certificate chain.
|
certificate chain.
|
||||||
|
|
||||||
|
@ -83,11 +92,11 @@ Note that the commands above do *not* verify server certificate, so if you
|
||||||
want to be safe download with your workstations's browser and transfer the
|
want to be safe download with your workstations's browser and transfer the
|
||||||
file to your MikroTik device.
|
file to your MikroTik device.
|
||||||
|
|
||||||
* [ISRG Root X2](https://letsencrypt.org/certs/isrg-root-x2.pem)
|
* [ISRG Root X2 ↗️](https://letsencrypt.org/certs/isrg-root-x2.pem)
|
||||||
|
|
||||||
Then we import the certificate.
|
Then we import the certificate.
|
||||||
|
|
||||||
/certificate/import file-name=isrg-root-x2.pem passphrase="";
|
/certificate/import file-name="isrg-root-x2.pem" passphrase="";
|
||||||
|
|
||||||
Do not worry that the command is not shown - that happens because it contains
|
Do not worry that the command is not shown - that happens because it contains
|
||||||
a sensitive property, the passphrase.
|
a sensitive property, the passphrase.
|
||||||
|
@ -105,6 +114,8 @@ is shown.
|
||||||
|
|
||||||
Always make sure there are no certificates installed you do not know or want!
|
Always make sure there are no certificates installed you do not know or want!
|
||||||
|
|
||||||
|
#### Installation of scripts
|
||||||
|
|
||||||
All following commands will verify the server certificate. For validity the
|
All following commands will verify the server certificate. For validity the
|
||||||
certificate's lifetime is checked with local time, so make sure the device's
|
certificate's lifetime is checked with local time, so make sure the device's
|
||||||
date and time is set correctly!
|
date and time is set correctly!
|
||||||
|
@ -122,6 +133,9 @@ And finally load configuration and functions and add the scheduler.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
> 💡️ **Hint**: You see complaints regarding syntax errors? Most likely the
|
||||||
|
> RouterOS on your device is too old. Check for updates!
|
||||||
|
|
||||||
### Scheduled automatic updates
|
### Scheduled automatic updates
|
||||||
|
|
||||||
The last step is optional: Add this scheduler **only** if you want the
|
The last step is optional: Add this scheduler **only** if you want the
|
||||||
|
@ -191,7 +205,7 @@ Scheduler and events
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Most scripts are designed to run regularly from
|
Most scripts are designed to run regularly from
|
||||||
[scheduler](https://wiki.mikrotik.com/wiki/Manual:System/Scheduler). We just
|
[scheduler ↗️](https://wiki.mikrotik.com/wiki/Manual:System/Scheduler). We just
|
||||||
added `check-routeros-update`, so let's run it daily to make sure not to
|
added `check-routeros-update`, so let's run it daily to make sure not to
|
||||||
miss an update.
|
miss an update.
|
||||||
|
|
||||||
|
@ -214,60 +228,62 @@ There's much more to explore... Have fun!
|
||||||
Available scripts
|
Available scripts
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* [Find and remove access list duplicates](doc/accesslist-duplicates.md)
|
* [Find and remove access list duplicates](doc/accesslist-duplicates.md) (`accesslist-duplicates`)
|
||||||
* [Upload backup to Mikrotik cloud](doc/backup-cloud.md)
|
* [Upload backup to Mikrotik cloud](doc/backup-cloud.md) (`backup-cloud`)
|
||||||
* [Send backup via e-mail](doc/backup-email.md)
|
* [Send backup via e-mail](doc/backup-email.md) (`backup-email`)
|
||||||
* [Save configuration to fallback partition](doc/backup-partition.md)
|
* [Save configuration to fallback partition](doc/backup-partition.md) (`backup-partition`)
|
||||||
* [Upload backup to server](doc/backup-upload.md)
|
* [Upload backup to server](doc/backup-upload.md) (`backup-upload`)
|
||||||
* [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md)
|
* [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) (`capsman-download-packages`)
|
||||||
* [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md)
|
* [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) (`capsman-rolling-upgrade`)
|
||||||
* [Renew locally issued certificates](doc/certificate-renew-issued.md)
|
* [Renew locally issued certificates](doc/certificate-renew-issued.md) (`certificate-renew-issued`)
|
||||||
* [Renew certificates and notify on expiration](doc/check-certificates.md)
|
* [Renew certificates and notify on expiration](doc/check-certificates.md) (`check-certificates`)
|
||||||
* [Notify about health state](doc/check-health.md)
|
* [Notify about health state](doc/check-health.md) (`check-health`)
|
||||||
* [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md)
|
* [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md) (`check-lte-firmware-upgrade`)
|
||||||
* [Notify on RouterOS update](doc/check-routeros-update.md)
|
* [Check perpetual license on CHR](doc/check-perpetual-license.md) (`check-perpetual-license`)
|
||||||
* [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md)
|
* [Notify on RouterOS update](doc/check-routeros-update.md) (`check-routeros-update`)
|
||||||
* [Use wireless network with daily psk](doc/daily-psk.md)
|
* [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md) (`collect-wireless-mac`)
|
||||||
* [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md)
|
* [Use wireless network with daily psk](doc/daily-psk.md) (`daily-psk`)
|
||||||
* [Create DNS records for DHCP leases](doc/dhcp-to-dns.md)
|
* [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) (`dhcp-lease-comment`)
|
||||||
* [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md)
|
* [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) (`dhcp-to-dns`)
|
||||||
* [Download, import and update firewall address-lists](doc/fw-addr-lists.md)
|
* [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md) (`firmware-upgrade-reboot`)
|
||||||
* [Wait for global functions und modules](doc/global-wait.md)
|
* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) (`fw-addr-lists`)
|
||||||
* [Send GPS position to server](doc/gps-track.md)
|
* [Wait for global functions und modules](doc/global-wait.md) (`global-wait`)
|
||||||
* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md)
|
* [Send GPS position to server](doc/gps-track.md) (`gps-track`)
|
||||||
* [Create DNS records for IPSec peers](doc/ipsec-to-dns.md)
|
* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) (`hotspot-to-wpa` & `hotspot-to-wpa-cleanup`)
|
||||||
* [Update configuration on IPv6 prefix change](doc/ipv6-update.md)
|
* [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) (`ipsec-to-dns`)
|
||||||
* [Manage IP addresses with bridge status](doc/ip-addr-bridge.md)
|
* [Update configuration on IPv6 prefix change](doc/ipv6-update.md) (`ipv6-update`)
|
||||||
* [Run other scripts on DHCP lease](doc/lease-script.md)
|
* [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) (`ip-addr-bridge`)
|
||||||
* [Manage LEDs dark mode](doc/leds-mode.md)
|
* [Run other scripts on DHCP lease](doc/lease-script.md) (`lease-script`)
|
||||||
* [Forward log messages via notification](doc/log-forward.md)
|
* [Manage LEDs dark mode](doc/leds-mode.md) (`leds-day-mode`, `leds-night-mode` & `leds-toggle-mode`)
|
||||||
* [Mode button with multiple presses](doc/mode-button.md)
|
* [Forward log messages via notification](doc/log-forward.md) (`log-forward`)
|
||||||
* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md)
|
* [Mode button with multiple presses](doc/mode-button.md) (`mode-button`)
|
||||||
* [Notify on host up and down](doc/netwatch-notify.md)
|
* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) (`netwatch-dns`)
|
||||||
* [Visualize OSPF state via LEDs](doc/ospf-to-leds.md)
|
* [Notify on host up and down](doc/netwatch-notify.md) (`netwatch-notify`)
|
||||||
* [Manage system update](doc/packages-update.md)
|
* [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) (`ospf-to-leds`)
|
||||||
* [Run scripts on ppp connection](doc/ppp-on-up.md)
|
* [Manage system update](doc/packages-update.md) (`packages-update`)
|
||||||
* [Act on received SMS](doc/sms-action.md)
|
* [Run scripts on ppp connection](doc/ppp-on-up.md) (`ppp-on-up`)
|
||||||
* [Forward received SMS](doc/sms-forward.md)
|
* [Act on received SMS](doc/sms-action.md) (`sms-action`)
|
||||||
* [Play Super Mario theme](doc/super-mario-theme.md)
|
* [Forward received SMS](doc/sms-forward.md) (`sms-forward`)
|
||||||
* [Chat with your router and send commands via Telegram bot](doc/telegram-chat.md)
|
* [Play Super Mario theme](doc/super-mario-theme.md) (`super-mario-theme`)
|
||||||
* [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md)
|
* [Chat with your router and send commands via Telegram bot](doc/telegram-chat.md) (`telegram-chat`)
|
||||||
* [Update GRE configuration with dynamic addresses](doc/update-gre-address.md)
|
* [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) (`unattended-lte-firmware-upgrade`)
|
||||||
* [Update tunnelbroker configuration](doc/update-tunnelbroker.md)
|
* [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) (`update-gre-address`)
|
||||||
|
* [Update tunnelbroker configuration](doc/update-tunnelbroker.md) (`update-tunnelbroker`)
|
||||||
|
|
||||||
Available modules
|
Available modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* [Manage ports in bridge](doc/mod/bridge-port-to.md)
|
* [Manage ports in bridge](doc/mod/bridge-port-to.md) (`mod/bridge-port-to`)
|
||||||
* [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md)
|
* [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) (`mod/bridge-port-vlan`)
|
||||||
* [Inspect variables](doc/mod/inspectvar.md)
|
* [Inspect variables](doc/mod/inspectvar.md) (`mod/inspectvar`)
|
||||||
* [IP address calculation](doc/mod/ipcalc.md)
|
* [IP address calculation](doc/mod/ipcalc.md) (`mod/ipcalc`)
|
||||||
* [Send notifications via e-mail](doc/mod/notification-email.md)
|
* [Send notifications via e-mail](doc/mod/notification-email.md) (`mod/notification-email`)
|
||||||
* [Send notifications via Matrix](doc/mod/notification-matrix.md)
|
* [Send notifications via Gotify](doc/mod/notification-gotify.md) (`mod/notification-gotify`)
|
||||||
* [Send notifications via Ntfy](doc/mod/notification-ntfy.md)
|
* [Send notifications via Matrix](doc/mod/notification-matrix.md) (`mod/notification-matrix`)
|
||||||
* [Send notifications via Telegram](doc/mod/notification-telegram.md)
|
* [Send notifications via Ntfy](doc/mod/notification-ntfy.md) (`mod/notification-ntfy`)
|
||||||
* [Download script and run it once](doc/mod/scriptrunonce.md)
|
* [Send notifications via Telegram](doc/mod/notification-telegram.md) (`mod/notification-telegram`)
|
||||||
* [Import ssh keys for public key authentication](doc/mod/ssh-keys-import.md)
|
* [Download script and run it once](doc/mod/scriptrunonce.md) (`mod/scriptrunonce`)
|
||||||
|
* [Import ssh keys for public key authentication](doc/mod/ssh-keys-import.md) (`mod/ssh-keys-import`)
|
||||||
|
|
||||||
Installing custom scripts & modules
|
Installing custom scripts & modules
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
@ -324,7 +340,7 @@ Possibly a scheduler and other configuration has to be removed as well.
|
||||||
Contact
|
Contact
|
||||||
-------
|
-------
|
||||||
|
|
||||||
We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)!
|
We have a Telegram Group [RouterOS-Scripts ↗️](https://t.me/routeros_scripts)!
|
||||||
|
|
||||||
[](https://t.me/routeros_scripts)
|
[](https://t.me/routeros_scripts)
|
||||||
|
|
||||||
|
@ -348,7 +364,7 @@ at github.
|
||||||
This project is developed in private spare time and usage is free of charge
|
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
|
for you. If you like the scripts and think this is of value for you or your
|
||||||
business please consider to
|
business please consider to
|
||||||
[donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J).
|
[donate with PayPal ↗️](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J).
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)
|
||||||
|
|
||||||
|
@ -367,6 +383,21 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
[GNU General Public License](COPYING.md) for more details.
|
[GNU General Public License](COPYING.md) for more details.
|
||||||
|
|
||||||
|
Disclaimer on external links
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Our website contains links to the websites of third parties ("external
|
||||||
|
links"). As the content of these websites is not under our control, we
|
||||||
|
cannot assume any liability for such external content. In all cases, the
|
||||||
|
provider of information of the linked websites is liable for the content
|
||||||
|
and accuracy of the information provided. At the point in time when the
|
||||||
|
links were placed, no infringements of the law were recognisable to us.
|
||||||
|
As soon as an infringement of the law becomes known to us, we will
|
||||||
|
immediately remove the link in question.
|
||||||
|
|
||||||
|
> 💡️ **Hint**: All external links are marked with an arrow pointing
|
||||||
|
> diagonally in an up-right (or north-east) direction (↗️).
|
||||||
|
|
||||||
Upstream
|
Upstream
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:local Seen ({});
|
:local Seen ({});
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
: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 ];
|
:local Mac [ /caps-man/access-list/get $AccList mac-address ];
|
||||||
:if ($Seen->$Mac = 1) do={
|
:if ($Seen->$Mac = 1) do={
|
||||||
/caps-man/access-list/print where mac-address=$Mac;
|
/caps-man/access-list/print without-paging where mac-address=$Mac;
|
||||||
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
||||||
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
@ -32,6 +32,6 @@
|
||||||
}
|
}
|
||||||
:set ($Seen->$Mac) 1;
|
:set ($Seen->$Mac) 1;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:local Seen ({});
|
:local Seen ({});
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
: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 ];
|
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
|
||||||
:if ($Seen->$Mac = 1) do={
|
:if ($Seen->$Mac = 1) do={
|
||||||
/interface/wireless/access-list/print where mac-address=$Mac;
|
/interface/wireless/access-list/print without-paging where mac-address=$Mac;
|
||||||
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
||||||
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
@ -32,6 +32,6 @@
|
||||||
}
|
}
|
||||||
:set ($Seen->$Mac) 1;
|
:set ($Seen->$Mac) 1;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:local Seen ({});
|
:local Seen ({});
|
||||||
|
@ -27,9 +27,9 @@
|
||||||
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
|
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
|
||||||
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
|
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
|
||||||
:if ($Seen->$Mac = 1) do={
|
:if ($Seen->$Mac = 1) do={
|
||||||
/caps-man/access-list/print where mac-address=$Mac;
|
/caps-man/access-list/print without-paging where mac-address=$Mac;
|
||||||
/interface/wifi/access-list/print where mac-address=$Mac;
|
/interface/wifi/access-list/print without-paging where mac-address=$Mac;
|
||||||
/interface/wireless/access-list/print where mac-address=$Mac;
|
/interface/wireless/access-list/print without-paging where mac-address=$Mac;
|
||||||
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
||||||
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
@ -41,6 +41,6 @@
|
||||||
}
|
}
|
||||||
:set ($Seen->$Mac) 1;
|
:set ($Seen->$Mac) 1;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:local Seen ({});
|
:local Seen ({});
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
|
||||||
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
|
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
|
||||||
:if ($Seen->$Mac = 1) do={
|
:if ($Seen->$Mac = 1) do={
|
||||||
/interface/wifi/access-list/print where mac-address=$Mac;
|
/interface/wifi/access-list/print without-paging where mac-address=$Mac;
|
||||||
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
|
||||||
|
|
||||||
:if ([ :typeof $Remove ] = "num") do={
|
:if ([ :typeof $Remove ] = "num") do={
|
||||||
|
@ -32,6 +32,6 @@
|
||||||
}
|
}
|
||||||
:set ($Seen->$Mac) 1;
|
:set ($Seen->$Mac) 1;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# upload backup to MikroTik cloud
|
# upload backup to MikroTik cloud
|
||||||
# https://rsc.eworm.de/doc/backup-cloud.md
|
# https://rsc.eworm.de/doc/backup-cloud.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global BackupRandomDelay;
|
:global BackupRandomDelay;
|
||||||
|
@ -99,6 +99,6 @@
|
||||||
:set PackagesUpdateBackupFailure true;
|
:set PackagesUpdateBackupFailure true;
|
||||||
}
|
}
|
||||||
$RmDir "tmpfs/backup-cloud";
|
$RmDir "tmpfs/backup-cloud";
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# create and email backup and config file
|
# create and email backup and config file
|
||||||
# https://rsc.eworm.de/doc/backup-email.md
|
# https://rsc.eworm.de/doc/backup-email.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global BackupPassword;
|
:global BackupPassword;
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
:global CleanName;
|
:global CleanName;
|
||||||
:global DeviceInfo;
|
:global DeviceInfo;
|
||||||
|
:global FileExists;
|
||||||
:global FormatLine;
|
:global FormatLine;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
|
@ -124,17 +125,19 @@
|
||||||
attach=$Attach; remove-attach=true });
|
attach=$Attach; remove-attach=true });
|
||||||
|
|
||||||
# wait for the mail to be sent
|
# wait for the mail to be sent
|
||||||
:local I 0;
|
:do {
|
||||||
:while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={
|
:retry {
|
||||||
:if ($I >= 120) do={
|
:if ([ $FileExists ($FilePath . ".conf") ".conf file" ] = true || \
|
||||||
$LogPrint warning $ScriptName ("Files are still available, sending e-mail failed.");
|
[ $FileExists ($FilePath . ".backup") "backup" ] = true || \
|
||||||
:set PackagesUpdateBackupFailure true;
|
[ $FileExists ($FilePath . ".rsc") "script" ] = true) do={
|
||||||
:set ExitOK true;
|
:error "Files are still available.";
|
||||||
:error false;
|
}
|
||||||
}
|
} delay=1s max=120;
|
||||||
:delay 1s;
|
} on-error={
|
||||||
:set I ($I + 1);
|
$LogPrint warning $ScriptName ("Files are still available, sending e-mail failed.");
|
||||||
|
:set PackagesUpdateBackupFailure true;
|
||||||
}
|
}
|
||||||
} on-error={
|
# do not remove the files here, as the mail is still queued!
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
} do={
|
||||||
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
# save configuration to fallback partition
|
# save configuration to fallback partition
|
||||||
# https://rsc.eworm.de/doc/backup-partition.md
|
# https://rsc.eworm.de/doc/backup-partition.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global BackupPartitionCopyBeforeFeatureUpdate;
|
:global BackupPartitionCopyBeforeFeatureUpdate;
|
||||||
|
@ -32,14 +32,15 @@
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/partitions/copy-to $FallbackTo;
|
/partitions/copy-to $FallbackTo;
|
||||||
$LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackToName . "'.");
|
$LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackToName . "'.");
|
||||||
:return true;
|
} do={
|
||||||
} on-error={
|
$LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . \
|
||||||
$LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackToName . "'!");
|
$FallbackToName . "': " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ $ScriptLock $ScriptName ] = false) do={
|
:if ([ $ScriptLock $ScriptName ] = false) do={
|
||||||
|
@ -107,20 +108,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/system/scheduler/add start-time=startup name="running-from-backup-partition" \
|
/system/scheduler/add start-time=startup name="running-from-backup-partition" \
|
||||||
on-event=(":log warning (\"Running from partition '\" . " . \
|
on-event=(":log warning (\"Running from partition '\" . " . \
|
||||||
"[ /partitions/get [ find where running ] name ] . \"'!\")");
|
"[ /partitions/get [ find where running ] name ] . \"'!\")");
|
||||||
/partitions/save-config-to $FallbackTo;
|
/partitions/save-config-to $FallbackTo;
|
||||||
/system/scheduler/remove "running-from-backup-partition";
|
/system/scheduler/remove "running-from-backup-partition";
|
||||||
$LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackToName . "'.");
|
$LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackToName . "'.");
|
||||||
} on-error={
|
} do={
|
||||||
/system/scheduler/remove [ find where name="running-from-backup-partition" ];
|
/system/scheduler/remove [ find where name="running-from-backup-partition" ];
|
||||||
$LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackToName . "'!");
|
$LogPrint error $ScriptName ("Failed saving configuration to partition '" . \
|
||||||
|
$FallbackToName . "': " . $Err);
|
||||||
:set PackagesUpdateBackupFailure true;
|
:set PackagesUpdateBackupFailure true;
|
||||||
:set ExitOK true;
|
:set ExitOK true;
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
# create and upload backup and config file
|
# create and upload backup and config file
|
||||||
# https://rsc.eworm.de/doc/backup-upload.md
|
# https://rsc.eworm.de/doc/backup-upload.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global BackupPassword;
|
:global BackupPassword;
|
||||||
|
@ -90,13 +90,13 @@
|
||||||
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
|
||||||
$WaitForFile ($FilePath . ".backup");
|
$WaitForFile ($FilePath . ".backup");
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup");
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup");
|
||||||
:set BackupFile [ /file/get ($FilePath . ".backup") ];
|
:set BackupFile [ /file/get ($FilePath . ".backup") ];
|
||||||
:set ($BackupFile->"name") ($FileName . ".backup");
|
:set ($BackupFile->"name") ($FileName . ".backup");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $ScriptName ("Uploading backup file failed!");
|
$LogPrint error $ScriptName ("Uploading backup file failed: " . $Err);
|
||||||
:set BackupFile "failed";
|
:set BackupFile "failed";
|
||||||
:set Failed 1;
|
:set Failed 1;
|
||||||
}
|
}
|
||||||
|
@ -109,13 +109,13 @@
|
||||||
/export terse show-sensitive file=$FilePath;
|
/export terse show-sensitive file=$FilePath;
|
||||||
$WaitForFile ($FilePath . ".rsc");
|
$WaitForFile ($FilePath . ".rsc");
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc");
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc");
|
||||||
:set ExportFile [ /file/get ($FilePath . ".rsc") ];
|
:set ExportFile [ /file/get ($FilePath . ".rsc") ];
|
||||||
:set ($ExportFile->"name") ($FileName . ".rsc");
|
:set ($ExportFile->"name") ($FileName . ".rsc");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $ScriptName ("Uploading configuration export failed!");
|
$LogPrint error $ScriptName ("Uploading configuration export failed: " . $Err);
|
||||||
:set ExportFile "failed";
|
:set ExportFile "failed";
|
||||||
:set Failed 1;
|
:set Failed 1;
|
||||||
}
|
}
|
||||||
|
@ -130,13 +130,13 @@
|
||||||
file=($FilePath . ".conf\00");
|
file=($FilePath . ".conf\00");
|
||||||
$WaitForFile ($FilePath . ".conf");
|
$WaitForFile ($FilePath . ".conf");
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \
|
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \
|
||||||
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf");
|
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf");
|
||||||
:set ConfigFile [ /file/get ($FilePath . ".conf") ];
|
:set ConfigFile [ /file/get ($FilePath . ".conf") ];
|
||||||
:set ($ConfigFile->"name") ($FileName . ".conf");
|
:set ($ConfigFile->"name") ($FileName . ".conf");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $ScriptName ("Uploading global-config-overlay failed!");
|
$LogPrint error $ScriptName ("Uploading global-config-overlay failed: " . $Err);
|
||||||
:set ConfigFile "failed";
|
:set ConfigFile "failed";
|
||||||
:set Failed 1;
|
:set Failed 1;
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,6 @@
|
||||||
:set PackagesUpdateBackupFailure true;
|
:set PackagesUpdateBackupFailure true;
|
||||||
}
|
}
|
||||||
$RmDir $DirName;
|
$RmDir $DirName;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,16 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CleanFilePath;
|
:global CleanFilePath;
|
||||||
:global DownloadPackage;
|
:global DownloadPackage;
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
:global RmFile;
|
:global RmFile;
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
|
:if ([ $FileGet $PackagePath ] = false) do={
|
||||||
:if ([ $MkDir $PackagePath ] = false) do={
|
:if ([ $MkDir $PackagePath ] = false) do={
|
||||||
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
||||||
$PackagePath . ") failed!");
|
$PackagePath . ") failed!");
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
"). Please place your packages!");
|
"). Please place your packages!");
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Package in=[ /file/find where type=package \
|
:foreach Package in=[ /file/find where type="package" \
|
||||||
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
||||||
:local File [ /file/get $Package ];
|
:local File [ /file/get $Package ];
|
||||||
:if ($File->"package-architecture" = "mips") do={
|
:if ($File->"package-architecture" = "mips") do={
|
||||||
|
@ -62,11 +63,11 @@
|
||||||
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
||||||
($File->"package-architecture") $PackagePath ] = true) do={
|
($File->"package-architecture") $PackagePath ] = true) do={
|
||||||
:set Updated true;
|
:set Updated true;
|
||||||
$RmFile $Package;
|
$RmFile ($File->"name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
|
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={
|
||||||
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
||||||
:foreach Arch in={ "arm"; "mipsbe" } do={
|
:foreach Arch in={ "arm"; "mipsbe" } do={
|
||||||
:foreach Package in={ "routeros"; "wireless" } do={
|
:foreach Package in={ "routeros"; "wireless" } do={
|
||||||
|
@ -87,6 +88,6 @@
|
||||||
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,16 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CleanFilePath;
|
:global CleanFilePath;
|
||||||
:global DownloadPackage;
|
:global DownloadPackage;
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
:global RmFile;
|
:global RmFile;
|
||||||
|
@ -44,7 +45,7 @@
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
|
:if ([ $FileGet $PackagePath ] = false) do={
|
||||||
:if ([ $MkDir $PackagePath ] = false) do={
|
:if ([ $MkDir $PackagePath ] = false) do={
|
||||||
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
||||||
$PackagePath . ") failed!");
|
$PackagePath . ") failed!");
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
"). Please place your packages!");
|
"). Please place your packages!");
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Package in=[ /file/find where type=package \
|
:foreach Package in=[ /file/find where type="package" \
|
||||||
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
||||||
:local File [ /file/get $Package ];
|
:local File [ /file/get $Package ];
|
||||||
:if ($File->"package-architecture" = "mips") do={
|
:if ($File->"package-architecture" = "mips") do={
|
||||||
|
@ -64,11 +65,11 @@
|
||||||
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
||||||
($File->"package-architecture") $PackagePath ] = true) do={
|
($File->"package-architecture") $PackagePath ] = true) do={
|
||||||
:set Updated true;
|
:set Updated true;
|
||||||
$RmFile $Package;
|
$RmFile ($File->"name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
|
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={
|
||||||
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
||||||
# NOT /interface/wifi/ #
|
# NOT /interface/wifi/ #
|
||||||
:foreach Arch in={ "arm"; "mipsbe" } do={
|
:foreach Arch in={ "arm"; "mipsbe" } do={
|
||||||
|
@ -98,6 +99,6 @@
|
||||||
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,16 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CleanFilePath;
|
:global CleanFilePath;
|
||||||
:global DownloadPackage;
|
:global DownloadPackage;
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
:global RmFile;
|
:global RmFile;
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
|
:if ([ $FileGet $PackagePath ] = false) do={
|
||||||
:if ([ $MkDir $PackagePath ] = false) do={
|
:if ([ $MkDir $PackagePath ] = false) do={
|
||||||
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
$LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \
|
||||||
$PackagePath . ") failed!");
|
$PackagePath . ") failed!");
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
"). Please place your packages!");
|
"). Please place your packages!");
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Package in=[ /file/find where type=package \
|
:foreach Package in=[ /file/find where type="package" \
|
||||||
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
|
||||||
:local File [ /file/get $Package ];
|
:local File [ /file/get $Package ];
|
||||||
:if ($File->"package-architecture" = "mips") do={
|
:if ($File->"package-architecture" = "mips") do={
|
||||||
|
@ -62,11 +63,11 @@
|
||||||
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
|
||||||
($File->"package-architecture") $PackagePath ] = true) do={
|
($File->"package-architecture") $PackagePath ] = true) do={
|
||||||
:set Updated true;
|
:set Updated true;
|
||||||
$RmFile $Package;
|
$RmFile ($File->"name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
|
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={
|
||||||
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
$LogPrint info $ScriptName ("No packages available, downloading default set.");
|
||||||
:foreach Arch in={ "arm"; "arm64" } do={
|
:foreach Arch in={ "arm"; "arm64" } do={
|
||||||
:local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" };
|
:local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" };
|
||||||
|
@ -89,6 +90,6 @@
|
||||||
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -45,6 +45,6 @@
|
||||||
:delay ($Delay . "s");
|
:delay ($Delay . "s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -53,6 +53,6 @@
|
||||||
:delay ($Delay . "s");
|
:delay ($Delay . "s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -46,6 +46,6 @@
|
||||||
:delay ($Delay . "s");
|
:delay ($Delay . "s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# renew locally issued certificates
|
# renew locally issued certificates
|
||||||
# https://rsc.eworm.de/doc/certificate-renew-issued.md
|
# https://rsc.eworm.de/doc/certificate-renew-issued.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CertIssuedExportPass;
|
:global CertIssuedExportPass;
|
||||||
|
@ -47,6 +47,6 @@
|
||||||
$LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . "'.");
|
$LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ DOMAINS_DUAL = \
|
||||||
git.eworm.de/ISRG-Root-X2 \
|
git.eworm.de/ISRG-Root-X2 \
|
||||||
lists.blocklist.de/Certum-Trusted-Network-CA \
|
lists.blocklist.de/Certum-Trusted-Network-CA \
|
||||||
matrix.org/GTS-Root-R4 \
|
matrix.org/GTS-Root-R4 \
|
||||||
raw.githubusercontent.com/DigiCert-Global-Root-G2 \
|
raw.githubusercontent.com/USERTrust-RSA-Certification-Authority \
|
||||||
rsc.eworm.de/ISRG-Root-X2 \
|
rsc.eworm.de/ISRG-Root-X2 \
|
||||||
upgrade.mikrotik.com/ISRG-Root-X1
|
upgrade.mikrotik.com/ISRG-Root-X1
|
||||||
DOMAINS_IPV4 = \
|
DOMAINS_IPV4 = \
|
||||||
|
|
41
certs/USERTrust-RSA-Certification-Authority.pem
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
|
||||||
|
# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
|
||||||
|
# Label: "USERTrust RSA Certification Authority"
|
||||||
|
# Serial: 2645093764781058787591871645665788717
|
||||||
|
# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5
|
||||||
|
# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e
|
||||||
|
# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||||
|
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||||
|
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||||
|
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||||
|
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||||
|
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||||
|
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||||
|
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||||
|
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||||
|
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||||
|
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||||
|
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||||
|
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||||
|
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||||
|
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||||
|
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||||
|
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||||
|
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||||
|
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||||
|
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||||
|
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||||
|
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||||
|
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||||
|
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||||
|
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||||
|
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||||
|
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||||
|
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||||
|
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||||
|
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||||
|
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||||
|
jjxDah2nGN59PRbxYvnKkKj9
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -9,11 +9,11 @@
|
||||||
# check for certificate validity
|
# check for certificate validity
|
||||||
# https://rsc.eworm.de/doc/check-certificates.md
|
# https://rsc.eworm.de/doc/check-certificates.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CertRenewTime;
|
:global CertRenewTime;
|
||||||
|
@ -48,21 +48,26 @@
|
||||||
:global UrlEncode;
|
:global UrlEncode;
|
||||||
:global WaitForFile;
|
:global WaitForFile;
|
||||||
|
|
||||||
:local Return false;
|
:foreach Type in={ "p12"; "pem" } do={
|
||||||
|
:local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type);
|
||||||
|
$LogPrint debug $ScriptName ("Trying type '" . $Type . "' for '" . $CertName . \
|
||||||
|
"' (file '" . $CertFileName . "')...");
|
||||||
|
|
||||||
:foreach Type in={ ".pem"; ".p12" } do={
|
|
||||||
:local CertFileName ([ $UrlEncode $FetchName ] . $Type);
|
|
||||||
:do {
|
:do {
|
||||||
/tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \
|
/tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \
|
||||||
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
|
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
|
||||||
$WaitForFile $CertFileName;
|
$WaitForFile $CertFileName;
|
||||||
|
|
||||||
:local DecryptionFailed true;
|
:local DecryptionFailed true;
|
||||||
:foreach PassPhrase in=$CertRenewPass do={
|
:foreach I,PassPhrase in=$CertRenewPass do={
|
||||||
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
|
:do {
|
||||||
:if ($Result->"decryption-failures" = 0) do={
|
$LogPrint debug $ScriptName ("Trying " . $I . ". passphrase... ");
|
||||||
:set DecryptionFailed false;
|
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
|
||||||
}
|
:if ($Result->"decryption-failures" = 0) do={
|
||||||
|
$LogPrint debug $ScriptName ("Success!");
|
||||||
|
:set DecryptionFailed false;
|
||||||
|
}
|
||||||
|
} on-error={ }
|
||||||
}
|
}
|
||||||
$RmFile $CertFileName;
|
$RmFile $CertFileName;
|
||||||
|
|
||||||
|
@ -77,13 +82,13 @@
|
||||||
$CertificateNameByCN [ /certificate/get $CertInChain common-name ];
|
$CertificateNameByCN [ /certificate/get $CertInChain common-name ];
|
||||||
}
|
}
|
||||||
|
|
||||||
:set Return true;
|
:return true;
|
||||||
} on-error={
|
} on-error={
|
||||||
$LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'.");
|
$LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:return $Return;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:local FormatInfo do={
|
:local FormatInfo do={
|
||||||
|
@ -232,6 +237,6 @@
|
||||||
", it is invalid after " . ($CertVal->"invalid-after") . ".");
|
", it is invalid after " . ($CertVal->"invalid-after") . ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# check for RouterOS health state
|
# check for RouterOS health state
|
||||||
# https://rsc.eworm.de/doc/check-health.md
|
# https://rsc.eworm.de/doc/check-health.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CheckHealthCPUUtilization;
|
:global CheckHealthCPUUtilization;
|
||||||
|
@ -89,10 +89,10 @@
|
||||||
:foreach Plugin in=$Plugins do={
|
:foreach Plugin in=$Plugins do={
|
||||||
:local PluginVal [ /system/script/get $Plugin ];
|
:local PluginVal [ /system/script/get $Plugin ];
|
||||||
:if ([ $ValidateSyntax ($PluginVal->"source") ] = true) do={
|
:if ([ $ValidateSyntax ($PluginVal->"source") ] = true) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/system/script/run $Plugin;
|
/system/script/run $Plugin;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed to run.");
|
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed to run: " . $Err);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed syntax validation, skipping.");
|
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed syntax validation, skipping.");
|
||||||
|
@ -105,6 +105,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:set CheckHealthPlugins;
|
:set CheckHealthPlugins;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# check for LTE firmware upgrade, send notification
|
# check for LTE firmware upgrade, send notification
|
||||||
# https://rsc.eworm.de/doc/check-lte-firmware-upgrade.md
|
# https://rsc.eworm.de/doc/check-lte-firmware-upgrade.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global SentLteFirmwareUpgradeNotification;
|
:global SentLteFirmwareUpgradeNotification;
|
||||||
|
@ -45,12 +45,12 @@
|
||||||
:local IntName [ /interface/lte/get $Interface name ];
|
:local IntName [ /interface/lte/get $Interface name ];
|
||||||
:local Firmware;
|
:local Firmware;
|
||||||
:local Info;
|
:local Info;
|
||||||
:do {
|
:onerror Err {
|
||||||
:set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ];
|
:set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ];
|
||||||
:set Info [ /interface/lte/monitor $Interface once as-value ];
|
:set Info [ /interface/lte/monitor $Interface once as-value ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint debug $ScriptName ("Could not get latest LTE firmware version for interface " . \
|
$LogPrint debug $ScriptName ("Could not get latest LTE firmware version for interface " . \
|
||||||
$IntName . ".");
|
$IntName . ": " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,6 @@
|
||||||
:foreach Interface in=[ /interface/lte/find ] do={
|
:foreach Interface in=[ /interface/lte/find ] do={
|
||||||
$CheckInterface $ScriptName $Interface;
|
$CheckInterface $ScriptName $Interface;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
78
check-perpetual-license.rsc
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: check-perpetual-license
|
||||||
|
# Copyright (c) 2025 Christian Hesse <mail@eworm.de>
|
||||||
|
# https://rsc.eworm.de/COPYING.md
|
||||||
|
#
|
||||||
|
# requires RouterOS, version=7.15
|
||||||
|
#
|
||||||
|
# check perpetual license on CHR
|
||||||
|
# https://rsc.eworm.de/doc/check-perpetual-license.md
|
||||||
|
|
||||||
|
:local ExitOK false;
|
||||||
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global SentCertificateNotification;
|
||||||
|
|
||||||
|
:global LogPrint;
|
||||||
|
:global ScriptLock;
|
||||||
|
:global SendNotification2;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ $ScriptLock $ScriptName ] = false) do={
|
||||||
|
:set ExitOK true;
|
||||||
|
:error false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:local License [ /system/license/get ];
|
||||||
|
:if ([ :typeof ($License->"deadline-at") ] != "str") do={
|
||||||
|
$LogPrint info $ScriptName ("This device does not have a perpetual license.");
|
||||||
|
:set ExitOK true;
|
||||||
|
:error true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($License->"next-renewal-at") ] = 0 && ($License->"limited-upgrades") = true) do={
|
||||||
|
$LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!");
|
||||||
|
:if ($SentCertificateNotification != "expired") do={
|
||||||
|
$SendNotification2 ({ origin=$ScriptName; \
|
||||||
|
subject=([ $SymbolForNotification "warning-sign" ] . "License expired!"); \
|
||||||
|
message=("Your license expired on " . ($License->"deadline-at") . \
|
||||||
|
", can no longer update RouterOS on " . $Identity . "...") });
|
||||||
|
:set SentCertificateNotification "expired";
|
||||||
|
}
|
||||||
|
:set ExitOK true;
|
||||||
|
:error true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :totime ($License->"deadline-at") ] - 3w < [ :timestamp ]) do={
|
||||||
|
$LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!");
|
||||||
|
:if ($SentCertificateNotification != "warning") do={
|
||||||
|
$SendNotification2 ({ origin=$ScriptName; \
|
||||||
|
subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \
|
||||||
|
message=("Your license failed to renew and is about to expire on " . \
|
||||||
|
($License->"deadline-at") . " on " . $Identity . "...") });
|
||||||
|
:set SentCertificateNotification "warning";
|
||||||
|
}
|
||||||
|
:set ExitOK true;
|
||||||
|
:error true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :typeof $SentCertificateNotification ] = "str" && \
|
||||||
|
[ :totime ($License->"deadline-at") ] - 4w > [ :timestamp ]) do={
|
||||||
|
$LogPrint info $ScriptName ("Your license was successfully renewed.");
|
||||||
|
$SendNotification2 ({ origin=$ScriptName; \
|
||||||
|
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "License renewed"); \
|
||||||
|
message=("Your license was successfully renewed on " . $Identity . \
|
||||||
|
". It is now valid until " . ($License->"deadline-at") . ".") });
|
||||||
|
:set SentCertificateNotification;
|
||||||
|
}
|
||||||
|
} do={
|
||||||
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
|
}
|
|
@ -9,11 +9,11 @@
|
||||||
# check for RouterOS update, send notification and/or install
|
# check for RouterOS update, send notification and/or install
|
||||||
# https://rsc.eworm.de/doc/check-routeros-update.md
|
# https://rsc.eworm.de/doc/check-routeros-update.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
:global EscapeForRegEx;
|
:global EscapeForRegEx;
|
||||||
:global FetchUserAgentStr;
|
:global FetchUserAgentStr;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
:global RebootForUpdate;
|
||||||
:global ScriptFromTerminal;
|
:global ScriptFromTerminal;
|
||||||
:global ScriptLock;
|
:global ScriptLock;
|
||||||
:global SendNotification2;
|
:global SendNotification2;
|
||||||
|
@ -62,8 +63,14 @@
|
||||||
$WaitFullyConnected;
|
$WaitFullyConnected;
|
||||||
|
|
||||||
:if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={
|
:if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={
|
||||||
:set ExitOK true;
|
:if ([ :typeof $RebootForUpdate ] = "nothing") do={
|
||||||
:error "A reboot for update is already scheduled.";
|
$LogPrint info $ScriptName ("Found a stale scheduler for reboot, removing.");
|
||||||
|
/system/scheduler/remove "_RebootForUpdate";
|
||||||
|
} else={
|
||||||
|
$LogPrint info $ScriptName ("A reboot for update is already scheduled.");
|
||||||
|
:set ExitOK true;
|
||||||
|
:error false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$LogPrint debug $ScriptName ("Checking for updates...");
|
$LogPrint debug $ScriptName ("Checking for updates...");
|
||||||
|
@ -140,13 +147,13 @@
|
||||||
|
|
||||||
:if ([ :len $SafeUpdateUrl ] > 0) do={
|
:if ([ :len $SafeUpdateUrl ] > 0) do={
|
||||||
:local Result;
|
:local Result;
|
||||||
:do {
|
:onerror Err {
|
||||||
:set Result [ /tool/fetch check-certificate=yes-without-crl \
|
:set Result [ /tool/fetch check-certificate=yes-without-crl \
|
||||||
($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \
|
($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \
|
||||||
"&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \
|
"&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \
|
||||||
output=user as-value ];
|
output=user as-value ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . ".");
|
$LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . ": " . $Err);
|
||||||
}
|
}
|
||||||
:if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={
|
:if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={
|
||||||
$LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is considered safe, updating...");
|
$LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is considered safe, updating...");
|
||||||
|
@ -213,6 +220,6 @@
|
||||||
" is available for downgrade.");
|
" is available for downgrade.");
|
||||||
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
:set SentRouterosUpdateNotification ($Update->"latest-version");
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -95,6 +95,6 @@
|
||||||
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -96,6 +96,6 @@
|
||||||
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -113,6 +113,6 @@
|
||||||
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -95,6 +95,6 @@
|
||||||
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
$LogPrint debug $ScriptName ("No mac address available... Ignoring.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
9
contrib/checksums.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# generate a checksums file as used by $ScriptInstallUpdate
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
md5sum $(find -name '*.rsc' | sort) | \
|
||||||
|
sed -e "s| \./||" -e 's|.rsc$||' | \
|
||||||
|
jq --raw-input --null-input '[ inputs | split (" ") | { (.[1]): (.[0]) }] | add' > 'checksums.json'
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
:global DailyPskMatchComment;
|
||||||
|
@ -91,6 +91,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
:global DailyPskMatchComment;
|
||||||
|
@ -90,6 +90,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
:global DailyPskMatchComment;
|
||||||
|
@ -106,6 +106,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global DailyPskMatchComment;
|
:global DailyPskMatchComment;
|
||||||
|
@ -91,6 +91,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -38,6 +38,6 @@
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -38,6 +38,6 @@
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -43,6 +43,6 @@
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -38,6 +38,6 @@
|
||||||
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# check DHCP leases and add/remove/update DNS entries
|
# check DHCP leases and add/remove/update DNS entries
|
||||||
# https://rsc.eworm.de/doc/dhcp-to-dns.md
|
# https://rsc.eworm.de/doc/dhcp-to-dns.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Domain;
|
:global Domain;
|
||||||
|
@ -125,6 +125,6 @@
|
||||||
$LogPrint debug $ScriptName ("No address available... Ignoring.");
|
$LogPrint debug $ScriptName ("No address available... Ignoring.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This script uploads
|
This script uploads
|
||||||
[binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup).
|
[binary backup to Mikrotik cloud ↗️](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup).
|
||||||
|
|
||||||
> ⚠️ **Warning**: The used command can hit errors that a script can with
|
> ⚠️ **Warning**: The used command can hit errors that a script can with
|
||||||
> workaround only. A notification *should* be sent anyway. But it can result
|
> workaround only. A notification *should* be sent anyway. But it can result
|
||||||
|
@ -49,6 +49,7 @@ The configuration goes to `global-config-overlay`, these are the parameters:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -17,7 +17,7 @@ Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This script saves the current configuration to fallback
|
This script saves the current configuration to fallback
|
||||||
[partition](https://wiki.mikrotik.com/wiki/Manual:Partitions).
|
[partition ↗️](https://wiki.mikrotik.com/wiki/Manual:Partitions).
|
||||||
It can also copy-over the RouterOS installation when run interactively
|
It can also copy-over the RouterOS installation when run interactively
|
||||||
or just before a feature update.
|
or just before a feature update.
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ The configuration goes to `global-config-overlay`, these are the parameters:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -51,6 +51,7 @@ subject alternative name (aka *Subject Alt Name* or *SAN*) can be used.
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -113,6 +113,7 @@ The configuration goes to `global-config-overlay`, these are the parameters:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -44,7 +44,9 @@ Configuration
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
[matrix](mod/notification-matrix.md) and/or
|
[gotify](mod/notification-gotify.md),
|
||||||
|
[matrix](mod/notification-matrix.md),
|
||||||
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
||||||
See also
|
See also
|
||||||
|
|
BIN
doc/check-perpetual-license.d/notification.avif
Normal file
After Width: | Height: | Size: 3.9 KiB |
71
doc/check-perpetual-license.md
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
Check perpetual license on CHR
|
||||||
|
==============================
|
||||||
|
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/stargazers)
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/network)
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/watchers)
|
||||||
|
[](https://mikrotik.com/download/changelogs/)
|
||||||
|
[](https://t.me/routeros_scripts)
|
||||||
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)
|
||||||
|
|
||||||
|
[⬅️ Go back to main README](../README.md)
|
||||||
|
|
||||||
|
> ℹ️ **Info**: This script can not be used on its own but requires the base
|
||||||
|
> installation. See [main README](../README.md) for details.
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
On *Cloud Hosted Router* (*CHR*) the licensing is perpetual: Buy once, use
|
||||||
|
forever - but it needs regular renewal. This script checks licensing state
|
||||||
|
and sends a notification to warn before expiration.
|
||||||
|
|
||||||
|
### Sample notification
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Requirements and installation
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Just install the script:
|
||||||
|
|
||||||
|
$ScriptInstallUpdate check-perpetual-license;
|
||||||
|
|
||||||
|
And add a scheduler for automatic update notification:
|
||||||
|
|
||||||
|
/system/scheduler/add interval=1d name=check-perpetual-license on-event="/system/script/run check-perpetual-license;" start-time=startup;
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
No extra configuration is required for this script, but notification
|
||||||
|
settings are required for
|
||||||
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
|
[matrix](mod/notification-matrix.md),
|
||||||
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
||||||
|
Usage and invocation
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Be notified when run from scheduler or run it manually:
|
||||||
|
|
||||||
|
/system/script/run check-perpetual-license;
|
||||||
|
|
||||||
|
Tips & Tricks
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The script checks for full connectivity before acting, so scheduling at
|
||||||
|
startup is perfectly valid:
|
||||||
|
|
||||||
|
/system/scheduler/add name=check-perpetual-license@startup on-event="/system/script/run check-perpetual-license;" start-time=startup;
|
||||||
|
|
||||||
|
See also
|
||||||
|
--------
|
||||||
|
|
||||||
|
* [Notify on RouterOS update](check-routeros-update.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
[⬅️ Go back to main README](../README.md)
|
||||||
|
[⬆️ Go back to top](#top)
|
|
@ -30,8 +30,8 @@ automatically is supported.
|
||||||
> ⚠️ **Warning**: Installing updates is important from a security point
|
> ⚠️ **Warning**: Installing updates is important from a security point
|
||||||
> of view. At the same time it can be source of serve breakage. So test
|
> of view. At the same time it can be source of serve breakage. So test
|
||||||
> versions in lab and read
|
> versions in lab and read
|
||||||
> [changelog](https://mikrotik.com/download/changelogs/) and
|
> [changelog ↗️](https://mikrotik.com/download/changelogs/) and
|
||||||
> [forum](https://forum.mikrotik.com/viewforum.php?f=21) before deploying
|
> [forum ↗️](https://forum.mikrotik.com/viewforum.php?f=21) before deploying
|
||||||
> to your production environment! Automatic updates should be handled
|
> to your production environment! Automatic updates should be handled
|
||||||
> with care!
|
> with care!
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ The configuration goes to `global-config-overlay`, these are the parameters:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
@ -99,6 +100,7 @@ startup is perfectly valid:
|
||||||
See also
|
See also
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
* [Check perpetual license on CHR](check-perpetual-license.md)
|
||||||
* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md)
|
* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md)
|
||||||
* [Manage system update](packages-update.md)
|
* [Manage system update](packages-update.md)
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ entries are to be added.
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -79,6 +79,7 @@ For legacy local interface:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[trix](mod/notification-matrix.md),
|
[trix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -19,10 +19,10 @@ Description
|
||||||
This script downloads, imports and updates firewall address-lists. Its main
|
This script downloads, imports and updates firewall address-lists. Its main
|
||||||
purpose is to block attacking ip addresses, spam hosts, command-and-control
|
purpose is to block attacking ip addresses, spam hosts, command-and-control
|
||||||
servers and similar malicious entities. The default configuration contains a
|
servers and similar malicious entities. The default configuration contains a
|
||||||
[collective list by GitHub user @stamparm](https://github.com/stamparm/ipsum),
|
[collective list by GitHub user @stamparm ↗️](https://github.com/stamparm/ipsum),
|
||||||
lists from [dshield.org](https://dshield.org/) and
|
lists from [dshield.org ↗️](https://dshield.org/) and
|
||||||
[blocklist.de](https://www.blocklist.de/), and lists from
|
[blocklist.de ↗️](https://www.blocklist.de/), and lists from
|
||||||
[spamhaus.org](https://spamhaus.org/) are prepared.
|
[spamhaus.org ↗️](https://spamhaus.org/) are prepared.
|
||||||
|
|
||||||
The address-lists are updated in place, so after initial import you will not
|
The address-lists are updated in place, so after initial import you will not
|
||||||
see situation when the lists are not populated.
|
see situation when the lists are not populated.
|
||||||
|
@ -33,6 +33,9 @@ certificate is checked.
|
||||||
> ⚠️ **Warning**: The script does not limit the size of a list, but keep in
|
> ⚠️ **Warning**: The script does not limit the size of a list, but keep in
|
||||||
> mind that huge lists can exhaust your device's resources (RAM and CPU),
|
> mind that huge lists can exhaust your device's resources (RAM and CPU),
|
||||||
> and may take a long time to process.
|
> and may take a long time to process.
|
||||||
|
> Even crashes for the complete scripting (and CLI) subsystem are possible.
|
||||||
|
> This should be logged accordingly with warnings when global functions are
|
||||||
|
> reloaded from scheduler.
|
||||||
|
|
||||||
Requirements and installation
|
Requirements and installation
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
|
@ -22,15 +22,15 @@ server (see `/system/logging`). This has some limitation, however:
|
||||||
* does not work early after boot if network connectivity is not
|
* does not work early after boot if network connectivity is not
|
||||||
yet established, or breaks intermittently
|
yet established, or breaks intermittently
|
||||||
* lots of messages generate a flood of mails
|
* lots of messages generate a flood of mails
|
||||||
* Matrix, Ntfy and Telegram are not supported
|
* Gotify, Matrix, Ntfy and Telegram are not supported
|
||||||
|
|
||||||
The script works around the limitations, for example it does:
|
The script works around the limitations, for example it does:
|
||||||
|
|
||||||
* read from `/log`, including messages from early boot
|
* read from `/log`, including messages from early boot
|
||||||
* skip multi-repeated messages
|
* skip multi-repeated messages
|
||||||
* rate-limit itself to mitigate flooding
|
* rate-limit itself to mitigate flooding
|
||||||
* forward via notification (which includes *e-mail*, *Matrix*, *Ntfy* and
|
* forward via notification (which includes *e-mail*, *Gotify*, *Matrix*,
|
||||||
*Telegram* when installed and configured, see below)
|
*Ntfy* and *Telegram* when installed and configured, see below)
|
||||||
|
|
||||||
It is intended to be run periodically from scheduler, then collects new
|
It is intended to be run periodically from scheduler, then collects new
|
||||||
log messages and forwards them via notification.
|
log messages and forwards them via notification.
|
||||||
|
@ -72,7 +72,7 @@ The configuration goes to `global-config-overlay`, these are the parameters:
|
||||||
> your local `global-config-overlay` and modify it to your specific needs.
|
> your local `global-config-overlay` and modify it to your specific needs.
|
||||||
|
|
||||||
These patterns are matched as
|
These patterns are matched as
|
||||||
[regular expressions](https://wiki.mikrotik.com/wiki/Manual:Regular_Expressions).
|
[regular expressions ↗️](https://wiki.mikrotik.com/wiki/Manual:Regular_Expressions).
|
||||||
To forward **all** (ignoring severity) log messages with topics `account`
|
To forward **all** (ignoring severity) log messages with topics `account`
|
||||||
(which includes user logins) and `dhcp` you need something like:
|
(which includes user logins) and `dhcp` you need something like:
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ To forward **all** (ignoring severity) log messages with topics `account`
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -32,7 +32,7 @@ Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Set up your device's
|
Set up your device's
|
||||||
[e-mail settings](https://wiki.mikrotik.com/wiki/Manual:Tools/email).
|
[e-mail settings ↗️](https://wiki.mikrotik.com/wiki/Manual:Tools/email).
|
||||||
Also make sure the device has correct time configured, best is to set up
|
Also make sure the device has correct time configured, best is to set up
|
||||||
the ntp client.
|
the ntp client.
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ function available:
|
||||||
See also
|
See also
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
* [Send notifications via Gotify](notification-gotify.md)
|
||||||
* [Send notifications via Matrix](notification-matrix.md)
|
* [Send notifications via Matrix](notification-matrix.md)
|
||||||
* [Send notifications via Ntfy](notification-ntfy.md)
|
* [Send notifications via Ntfy](notification-ntfy.md)
|
||||||
* [Send notifications via Telegram](notification-telegram.md)
|
* [Send notifications via Telegram](notification-telegram.md)
|
||||||
|
|
BIN
doc/mod/notification-gotify.d/appsetup.avif
Normal file
After Width: | Height: | Size: 18 KiB |
97
doc/mod/notification-gotify.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
Send notifications via Gotify
|
||||||
|
===========================
|
||||||
|
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/stargazers)
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/network)
|
||||||
|
[](https://github.com/eworm-de/routeros-scripts/watchers)
|
||||||
|
[](https://mikrotik.com/download/changelogs/)
|
||||||
|
[](https://t.me/routeros_scripts)
|
||||||
|
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)
|
||||||
|
|
||||||
|
[⬅️ Go back to main README](../../README.md)
|
||||||
|
|
||||||
|
> ℹ️️ **Info**: This module can not be used on its own but requires the base
|
||||||
|
> installation. See [main README](../../README.md) for details.
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This module adds support for sending notifications via
|
||||||
|
[Gotify ↗️](https://gotify.net/). A queue is used to make sure
|
||||||
|
notifications are not lost on failure but sent later.
|
||||||
|
|
||||||
|
Requirements and installation
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Just install the module:
|
||||||
|
|
||||||
|
$ScriptInstallUpdate mod/notification-gotify;
|
||||||
|
|
||||||
|
Also deploy the [Gotify server ↗️](https://github.com/gotify/server) and
|
||||||
|
optionally install a Gotify client on your mobile device.
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Follow the [Installation ↗️](https://gotify.net/docs/install) instructions
|
||||||
|
and the [First Login ↗️](https://gotify.net/docs/first-login) setup. Once
|
||||||
|
you have a user and account you can start creating apps. Each app is an
|
||||||
|
independent notification feed for a device or application.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
On creation apps are assigned a *Token* for authentification, you will need
|
||||||
|
that in configuration.
|
||||||
|
|
||||||
|
Edit `global-config-overlay`, add `GotifyServer` with your server address
|
||||||
|
(just the address, no protocol - `https://` is assumed) and `GotifyToken`
|
||||||
|
with the *Token* from your configured app on the Gotify server. Then reload
|
||||||
|
the configuration.
|
||||||
|
|
||||||
|
> ℹ️ **Info**: Copy relevant configuration from
|
||||||
|
> [`global-config`](../../global-config.rsc) (the one without `-overlay`) to
|
||||||
|
> your local `global-config-overlay` and modify it to your specific needs.
|
||||||
|
|
||||||
|
For a custom service installing an additional certificate may be required.
|
||||||
|
You may want to install that certificate manually, after finding the
|
||||||
|
[certificate name from browser](../../CERTIFICATES.md).
|
||||||
|
|
||||||
|
Usage and invocation
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
There's nothing special to do. Every script or function sending a notification
|
||||||
|
will now send it to your Gotify application feed.
|
||||||
|
|
||||||
|
But of course you can use the function to send notifications directly. Give
|
||||||
|
it a try:
|
||||||
|
|
||||||
|
$SendGotify "Subject..." "Body...";
|
||||||
|
|
||||||
|
Alternatively this sends a notification with all available and configured
|
||||||
|
methods:
|
||||||
|
|
||||||
|
$SendNotification "Subject..." "Body...";
|
||||||
|
|
||||||
|
To use the functions in your own scripts you have to declare them first.
|
||||||
|
Place this before you call them:
|
||||||
|
|
||||||
|
:global SendGotify;
|
||||||
|
:global SendNotification;
|
||||||
|
|
||||||
|
In case there is a situation when the queue needs to be purged there is a
|
||||||
|
function available:
|
||||||
|
|
||||||
|
$PurgeGotifyQueue;
|
||||||
|
|
||||||
|
See also
|
||||||
|
--------
|
||||||
|
|
||||||
|
* [Certificate name from browser](../../CERTIFICATES.md)
|
||||||
|
* [Send notifications via e-mail](notification-email.md)
|
||||||
|
* [Send notifications via Matrix](notification-matrix.md)
|
||||||
|
* [Send notifications via Ntfy](notification-ntfy.md)
|
||||||
|
* [Send notifications via Telegram](notification-telegram.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
[⬅️ Go back to main README](../../README.md)
|
||||||
|
[⬆️ Go back to top](#top)
|
|
@ -17,7 +17,7 @@ Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This module adds support for sending notifications via
|
This module adds support for sending notifications via
|
||||||
[Matrix](https://matrix.org/) via client server api. A queue is used to
|
[Matrix ↗️](https://matrix.org/) via client server api. A queue is used to
|
||||||
make sure notifications are not lost on failure but sent later.
|
make sure notifications are not lost on failure but sent later.
|
||||||
|
|
||||||
Requirements and installation
|
Requirements and installation
|
||||||
|
@ -131,6 +131,7 @@ See also
|
||||||
|
|
||||||
* [Certificate name from browser](../../CERTIFICATES.md)
|
* [Certificate name from browser](../../CERTIFICATES.md)
|
||||||
* [Send notifications via e-mail](notification-email.md)
|
* [Send notifications via e-mail](notification-email.md)
|
||||||
|
* [Send notifications via Gotify](notification-gotify.md)
|
||||||
* [Send notifications via Ntfy](notification-ntfy.md)
|
* [Send notifications via Ntfy](notification-ntfy.md)
|
||||||
* [Send notifications via Telegram](notification-telegram.md)
|
* [Send notifications via Telegram](notification-telegram.md)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This module adds support for sending notifications via
|
This module adds support for sending notifications via
|
||||||
[Ntfy](https://ntfy.sh/). A queue is used to make sure
|
[Ntfy ↗️](https://ntfy.sh/). A queue is used to make sure
|
||||||
notifications are not lost on failure but sent later.
|
notifications are not lost on failure but sent later.
|
||||||
|
|
||||||
Requirements and installation
|
Requirements and installation
|
||||||
|
@ -28,7 +28,7 @@ Just install the module:
|
||||||
$ScriptInstallUpdate mod/notification-ntfy;
|
$ScriptInstallUpdate mod/notification-ntfy;
|
||||||
|
|
||||||
Also install the Ntfy app on your mobile device or use the
|
Also install the Ntfy app on your mobile device or use the
|
||||||
[web app](https://ntfy.sh/app) in a browser of your choice.
|
[web app ↗️](https://ntfy.sh/app) in a browser of your choice.
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
@ -90,6 +90,7 @@ See also
|
||||||
|
|
||||||
* [Certificate name from browser](../../CERTIFICATES.md)
|
* [Certificate name from browser](../../CERTIFICATES.md)
|
||||||
* [Send notifications via e-mail](notification-email.md)
|
* [Send notifications via e-mail](notification-email.md)
|
||||||
|
* [Send notifications via Gotify](notification-gotify.md)
|
||||||
* [Send notifications via Matrix](notification-matrix.md)
|
* [Send notifications via Matrix](notification-matrix.md)
|
||||||
* [Send notifications via Telegram](notification-telegram.md)
|
* [Send notifications via Telegram](notification-telegram.md)
|
||||||
|
|
||||||
|
|
BIN
doc/mod/notification-telegram.d/getchatid.avif
Normal file
After Width: | Height: | Size: 3.8 KiB |
|
@ -17,7 +17,7 @@ Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This module adds support for sending notifications via
|
This module adds support for sending notifications via
|
||||||
[Telegram](https://telegram.org/) via bot api. A queue is used to make sure
|
[Telegram ↗️](https://telegram.org/) via bot api. A queue is used to make sure
|
||||||
notifications are not lost on failure but sent later.
|
notifications are not lost on failure but sent later.
|
||||||
|
|
||||||
Requirements and installation
|
Requirements and installation
|
||||||
|
@ -33,19 +33,26 @@ and create an account.
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Open Telegram, then start a chat with [BotFather](https://t.me/BotFather) and
|
Open Telegram, then start a chat with [BotFather ↗️](https://t.me/BotFather) and
|
||||||
create your own bot:
|
create your own bot:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Now open a chat with your bot and start it by clicking the `START` button.
|
Set that token from *BotFather* (use your own!) to `TelegramTokenId`, for
|
||||||
|
now just temporarily:
|
||||||
|
|
||||||
Open just another chat with [GetIDs Bot](https://t.me/getidsbot), again start
|
:set TelegramTokenId "5214364459:AAHLwf1o7ybbKDo6pY24Kd2bZ5rjCakDXTc";
|
||||||
with the `START` button. It will send you some information, including the
|
|
||||||
`id`, just below `You`.
|
Now open a chat with your bot and start it by clicking the `START` button,
|
||||||
|
then send your first message. Any text will do. On your device run
|
||||||
|
`$GetTelegramChatId` to retrieve the chat id:
|
||||||
|
|
||||||
|
$GetTelegramChatId;
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Finally edit `global-config-overlay`, add `TelegramTokenId` with the token
|
Finally edit `global-config-overlay`, add `TelegramTokenId` with the token
|
||||||
from *BotFather* and `TelegramChatId` with your id from *GetIDs Bot*. Then
|
from *BotFather* and `TelegramChatId` with your retrieved chat id. Then
|
||||||
reload the configuration.
|
reload the configuration.
|
||||||
|
|
||||||
> ℹ️ **Info**: Copy relevant configuration from
|
> ℹ️ **Info**: Copy relevant configuration from
|
||||||
|
@ -54,9 +61,10 @@ reload the configuration.
|
||||||
|
|
||||||
### Notifications to a group
|
### Notifications to a group
|
||||||
|
|
||||||
Sending notifications to a group is possible as well. Add your bot and the
|
Sending notifications to a group is possible as well. Add your bot to a group
|
||||||
*GetIDs Bot* to a group, then use the group's id (which starts with a dash)
|
and make it an admin (required for read access!) and send a message and run
|
||||||
for `TelegramChatId`. Then remove *GetIDs Bot* from group.
|
`$GetTelegramChatId` again. Then use that chat id (which starts with a dash)
|
||||||
|
for `TelegramChatId`.
|
||||||
|
|
||||||
Groups can enable the `Topics` feature. Use `TelegramThreadId` to send to a
|
Groups can enable the `Topics` feature. Use `TelegramThreadId` to send to a
|
||||||
specific topic in a group.
|
specific topic in a group.
|
||||||
|
@ -94,7 +102,7 @@ Tips & Tricks
|
||||||
### Set a profile photo
|
### Set a profile photo
|
||||||
|
|
||||||
You can use a profile photo for your bot to make it recognizable. Open the
|
You can use a profile photo for your bot to make it recognizable. Open the
|
||||||
chat with [BotFather](https://t.me/BotFather) and set it there.
|
chat with [BotFather ↗️](https://t.me/BotFather) and set it there.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -107,6 +115,7 @@ See also
|
||||||
|
|
||||||
* [Chat with your router and send commands via Telegram bot](../telegram-chat.md)
|
* [Chat with your router and send commands via Telegram bot](../telegram-chat.md)
|
||||||
* [Send notifications via e-mail](notification-email.md)
|
* [Send notifications via e-mail](notification-email.md)
|
||||||
|
* [Send notifications via Gotify](notification-gotify.md)
|
||||||
* [Send notifications via Matrix](notification-matrix.md)
|
* [Send notifications via Matrix](notification-matrix.md)
|
||||||
* [Send notifications via Ntfy](notification-ntfy.md)
|
* [Send notifications via Ntfy](notification-ntfy.md)
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ The hosts to be checked have to be added to netwatch with specific comment:
|
||||||
|
|
||||||
Also notification settings are required for
|
Also notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -46,8 +46,8 @@ Configuration
|
||||||
|
|
||||||
The configuration goes to `global-config-overlay`, this is the only parameter:
|
The configuration goes to `global-config-overlay`, this is the only parameter:
|
||||||
|
|
||||||
* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM
|
* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM and
|
||||||
and 5 AM)
|
5 AM), use a numerical value in days suffixed with a `d` to defer further
|
||||||
|
|
||||||
By modifying the scheduler's `start-time` you can force the reboot at
|
By modifying the scheduler's `start-time` you can force the reboot at
|
||||||
different time.
|
different time.
|
||||||
|
|
|
@ -56,6 +56,7 @@ The configuration goes to `global-config-overlay`, this is the only parameter:
|
||||||
|
|
||||||
Notification settings are required for
|
Notification settings are required for
|
||||||
[e-mail](mod/notification-email.md),
|
[e-mail](mod/notification-email.md),
|
||||||
|
[gotify](mod/notification-gotify.md),
|
||||||
[matrix](mod/notification-matrix.md),
|
[matrix](mod/notification-matrix.md),
|
||||||
[ntfy](mod/notification-ntfy.md) and/or
|
[ntfy](mod/notification-ntfy.md) and/or
|
||||||
[telegram](mod/notification-telegram.md).
|
[telegram](mod/notification-telegram.md).
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# install firmware upgrade, and reboot
|
# install firmware upgrade, and reboot
|
||||||
# https://rsc.eworm.de/doc/firmware-upgrade-reboot.md
|
# https://rsc.eworm.de/doc/firmware-upgrade-reboot.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -55,6 +55,6 @@
|
||||||
|
|
||||||
$LogPrint info $ScriptName ("Firmware upgrade successful, rebooting.");
|
$LogPrint info $ScriptName ("Firmware upgrade successful, rebooting.");
|
||||||
/system/reboot;
|
/system/reboot;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# download, import and update firewall address-lists
|
# download, import and update firewall address-lists
|
||||||
# https://rsc.eworm.de/doc/fw-addr-lists.md
|
# https://rsc.eworm.de/doc/fw-addr-lists.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global FwAddrLists;
|
:global FwAddrLists;
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
:global HumanReadableNum;
|
:global HumanReadableNum;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global LogPrintOnce;
|
:global LogPrintOnce;
|
||||||
|
:global LogPrintVerbose;
|
||||||
:global ScriptLock;
|
:global ScriptLock;
|
||||||
:global WaitFullyConnected;
|
:global WaitFullyConnected;
|
||||||
|
|
||||||
|
@ -36,12 +37,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:local GetBranch do={
|
||||||
|
:global EitherOr;
|
||||||
|
:return [ :pick [ :convert transform=md5 to=hex [ :pick $1 0 [ $EitherOr [ :find $1 "/" ] [ :len $1 ] ] ] ] 0 2 ];
|
||||||
|
}
|
||||||
|
|
||||||
:if ([ $ScriptLock $ScriptName ] = false) do={
|
:if ([ $ScriptLock $ScriptName ] = false) do={
|
||||||
:set ExitOK true;
|
:set ExitOK true;
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
$WaitFullyConnected;
|
$WaitFullyConnected;
|
||||||
|
|
||||||
|
:if ([ :len [ /log/find where topics=({"script"; "warning"}) \
|
||||||
|
message=("\$LogPrintOnce: The message is already in log, scripting subsystem may have crashed before!") ] ] > 0) do={
|
||||||
|
$LogPrintOnce warning $ScriptName ("Scripting subsystem may have crashed, possibly caused by us. Delaying!");
|
||||||
|
:delay 5m;
|
||||||
|
}
|
||||||
|
|
||||||
:local ListComment ("managed by " . $ScriptName);
|
:local ListComment ("managed by " . $ScriptName);
|
||||||
|
|
||||||
:foreach FwListName,FwList in=$FwAddrLists do={
|
:foreach FwListName,FwList in=$FwAddrLists do={
|
||||||
|
@ -99,17 +111,24 @@
|
||||||
:set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr"));
|
:set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr"));
|
||||||
}
|
}
|
||||||
:do {
|
:do {
|
||||||
|
:local Branch [ $GetBranch $Address ];
|
||||||
:if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={
|
:if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={
|
||||||
:set ($IPv4Addresses->$Address) $TimeOut;
|
:if ($Address ~ "/32\$") do={
|
||||||
|
:set Address [ :pick $Address 0 ([ :len $Address ] - 3) ];
|
||||||
|
}
|
||||||
|
:set ($IPv4Addresses->$Branch->$Address) $TimeOut;
|
||||||
:error true;
|
:error true;
|
||||||
}
|
}
|
||||||
:if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={
|
:if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={
|
||||||
:set ($IPv6Addresses->$Address) $TimeOut;
|
:if ([ :typeof [ :find $Address "/" ] ] = "nil") do={
|
||||||
|
:set Address ($Address . "/128");
|
||||||
|
}
|
||||||
|
:set ($IPv6Addresses->$Branch->$Address) $TimeOut;
|
||||||
:error true;
|
:error true;
|
||||||
}
|
}
|
||||||
:if ($Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={
|
:if ($Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={
|
||||||
:set ($IPv4Addresses->$Address) $TimeOut;
|
:set ($IPv4Addresses->$Branch->$Address) $TimeOut;
|
||||||
:set ($IPv6Addresses->$Address) $TimeOut;
|
:set ($IPv6Addresses->$Branch->$Address) $TimeOut;
|
||||||
:error true;
|
:error true;
|
||||||
}
|
}
|
||||||
} on-error={ }
|
} on-error={ }
|
||||||
|
@ -119,16 +138,18 @@
|
||||||
:foreach Entry in=[ /ip/firewall/address-list/find where \
|
:foreach Entry in=[ /ip/firewall/address-list/find where \
|
||||||
list=$FwListName comment=$ListComment ] do={
|
list=$FwListName comment=$ListComment ] do={
|
||||||
:local Address [ /ip/firewall/address-list/get $Entry address ];
|
:local Address [ /ip/firewall/address-list/get $Entry address ];
|
||||||
:if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={
|
:local Branch [ $GetBranch $Address ];
|
||||||
$LogPrint debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \
|
:local TimeOut ($IPv4Addresses->$Branch->$Address);
|
||||||
"' with " . ($IPv4Addresses->$Address) . ": " . $Address);
|
:if ([ :typeof $TimeOut ] = "time") do={
|
||||||
/ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address);
|
$LogPrintVerbose debug $ScriptName ("Renewing IPv4 address " . $Address . \
|
||||||
:set ($IPv4Addresses->$Address);
|
" in list '" . $FwListName . "' with " . $TimeOut . ".");
|
||||||
|
/ip/firewall/address-list/set $Entry timeout=$TimeOut;
|
||||||
|
:set ($IPv4Addresses->$Branch->$Address);
|
||||||
:set CntRenew ($CntRenew + 1);
|
:set CntRenew ($CntRenew + 1);
|
||||||
} else={
|
} else={
|
||||||
:if ($Failure = false) do={
|
:if ($Failure = false) do={
|
||||||
$LogPrint debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \
|
$LogPrintVerbose debug $ScriptName ("Removing IPv4 address " . $Address . \
|
||||||
"': " . $Address);
|
" from list '" . $FwListName . ".");
|
||||||
/ip/firewall/address-list/remove $Entry;
|
/ip/firewall/address-list/remove $Entry;
|
||||||
:set CntRemove ($CntRemove + 1);
|
:set CntRemove ($CntRemove + 1);
|
||||||
}
|
}
|
||||||
|
@ -138,47 +159,53 @@
|
||||||
:foreach Entry in=[ /ipv6/firewall/address-list/find where \
|
:foreach Entry in=[ /ipv6/firewall/address-list/find where \
|
||||||
list=$FwListName comment=$ListComment ] do={
|
list=$FwListName comment=$ListComment ] do={
|
||||||
:local Address [ /ipv6/firewall/address-list/get $Entry address ];
|
:local Address [ /ipv6/firewall/address-list/get $Entry address ];
|
||||||
:if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={
|
:local Branch [ $GetBranch $Address ];
|
||||||
$LogPrint debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \
|
:local TimeOut ($IPv6Addresses->$Branch->$Address);
|
||||||
"' with " . ($IPv6Addresses->$Address) . ": " . $Address);
|
:if ([ :typeof $TimeOut ] = "time") do={
|
||||||
/ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address);
|
$LogPrintVerbose debug $ScriptName ("Renewing IPv6 address " . $Address . \
|
||||||
:set ($IPv6Addresses->$Address);
|
" in list '" . $FwListName . "' with " . $TimeOut . ".");
|
||||||
|
/ipv6/firewall/address-list/set $Entry timeout=$TimeOut;
|
||||||
|
:set ($IPv6Addresses->$Branch->$Address);
|
||||||
:set CntRenew ($CntRenew + 1);
|
:set CntRenew ($CntRenew + 1);
|
||||||
} else={
|
} else={
|
||||||
:if ($Failure = false) do={
|
:if ($Failure = false) do={
|
||||||
$LogPrint debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \
|
$LogPrintVerbose debug $ScriptName ("Removing IPv6 address " . $Address . \
|
||||||
"': " . $Address);
|
" from list '" . $FwListName .".");
|
||||||
/ipv6/firewall/address-list/remove $Entry;
|
/ipv6/firewall/address-list/remove $Entry;
|
||||||
:set CntRemove ($CntRemove + 1);
|
:set CntRemove ($CntRemove + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Address,Timeout in=$IPv4Addresses do={
|
:foreach BranchName,Branch in=$IPv4Addresses do={
|
||||||
$LogPrint debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \
|
$LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName);
|
||||||
"' with " . $Timeout . ": " . $Address);
|
:foreach Address,Timeout in=$Branch do={
|
||||||
:do {
|
$LogPrintVerbose debug $ScriptName ("Adding IPv4 address " . $Address . \
|
||||||
/ip/firewall/address-list/add list=$FwListName comment=$ListComment \
|
" to list '" . $FwListName . "' with " . $Timeout . ".");
|
||||||
address=$Address timeout=$Timeout;
|
:onerror Err {
|
||||||
:set ($IPv4Addresses->$Address);
|
/ip/firewall/address-list/add list=$FwListName comment=$ListComment \
|
||||||
:set CntAdd ($CntAdd + 1);
|
address=$Address timeout=$Timeout;
|
||||||
} on-error={
|
:set CntAdd ($CntAdd + 1);
|
||||||
$LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \
|
} do={
|
||||||
"': " . $Address);
|
$LogPrint warning $ScriptName ("Failed to add IPv4 address " . $Address . \
|
||||||
|
" to list '" . $FwListName . "': " . $Err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Address,Timeout in=$IPv6Addresses do={
|
:foreach BranchName,Branch in=$IPv6Addresses do={
|
||||||
$LogPrint debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \
|
$LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName);
|
||||||
"' with " . $Timeout . ": " . $Address);
|
:foreach Address,Timeout in=$Branch do={
|
||||||
:do {
|
$LogPrintVerbose debug $ScriptName ("Adding IPv6 address " . $Address . \
|
||||||
/ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \
|
" to list '" . $FwListName . "' with " . $Timeout . ".");
|
||||||
address=$Address timeout=$Timeout;
|
:onerror Err {
|
||||||
:set ($IPv6Addresses->$Address);
|
/ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \
|
||||||
:set CntAdd ($CntAdd + 1);
|
address=$Address timeout=$Timeout;
|
||||||
} on-error={
|
:set CntAdd ($CntAdd + 1);
|
||||||
$LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \
|
} do={
|
||||||
"': " . $Address);
|
$LogPrint warning $ScriptName ("Failed to add IPv6 address " . $Address . \
|
||||||
|
" to list '" . $FwListName . "': " . $Err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +215,6 @@
|
||||||
" - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \
|
" - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \
|
||||||
" - removed: " . [ $HumanReadableNum $CntRemove 1000 ]);
|
" - removed: " . [ $HumanReadableNum $CntRemove 1000 ]);
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
# global configuration
|
# global configuration
|
||||||
# https://rsc.eworm.de/
|
# https://rsc.eworm.de/
|
||||||
|
|
||||||
|
# Warning: Do *NOT* copy this line to overlay!
|
||||||
|
:global GlobalConfigReady false;
|
||||||
|
# || ... but
|
||||||
|
# \||/ start
|
||||||
|
# \/ here!
|
||||||
|
|
||||||
# Set this to 'true' to disable news and change notifications.
|
# Set this to 'true' to disable news and change notifications.
|
||||||
:global NoNewsAndChangesNotification false;
|
:global NoNewsAndChangesNotification false;
|
||||||
|
|
||||||
|
@ -63,6 +69,12 @@
|
||||||
:global NtfyServerToken "";
|
:global NtfyServerToken "";
|
||||||
:global NtfyTopic "";
|
:global NtfyTopic "";
|
||||||
|
|
||||||
|
# You can send Gotify notifications. Configure these settings and
|
||||||
|
# install the module:
|
||||||
|
# $ScriptInstallUpdate mod/notification-gotify
|
||||||
|
:global GotifyServer "";
|
||||||
|
:global GotifyToken "";
|
||||||
|
|
||||||
# It is possible to override e-mail, Telegram, Matrix and Ntfy setting
|
# It is possible to override e-mail, Telegram, Matrix and Ntfy setting
|
||||||
# for every script. This is done in arrays, where 'Override' is appended
|
# for every script. This is done in arrays, where 'Override' is appended
|
||||||
# to the variable name, like this:
|
# to the variable name, like this:
|
||||||
|
@ -103,7 +115,7 @@
|
||||||
# cert="ISRG Root X2" };
|
# cert="ISRG Root X2" };
|
||||||
{ url="https://raw.githubusercontent.com/stamparm/ipsum/refs/heads/master/levels/4.txt";
|
{ url="https://raw.githubusercontent.com/stamparm/ipsum/refs/heads/master/levels/4.txt";
|
||||||
# # higher level (decrease the numerical value) for more addresses, and vice versa
|
# # higher level (decrease the numerical value) for more addresses, and vice versa
|
||||||
cert="DigiCert Global Root G2" };
|
cert="USERTrust RSA Certification Authority" };
|
||||||
{ url="https://www.dshield.org/block.txt"; cidr="/24";
|
{ url="https://www.dshield.org/block.txt"; cidr="/24";
|
||||||
cert="ISRG Root X1" };
|
cert="ISRG Root X1" };
|
||||||
{ url="https://lists.blocklist.de/lists/strongips.txt";
|
{ url="https://lists.blocklist.de/lists/strongips.txt";
|
||||||
|
@ -258,14 +270,20 @@
|
||||||
"cert2-cn"="4n0th3r-s3cr3t";
|
"cert2-cn"="4n0th3r-s3cr3t";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# /\ Warning: Do *NOT* copy
|
||||||
|
# /\7\ the code below to overlay!
|
||||||
|
# /_()_\ Things *will* break!
|
||||||
|
#
|
||||||
# load custom settings from overlay and snippets
|
# load custom settings from overlay and snippets
|
||||||
# Warning: Do *NOT* copy this code to overlay!
|
|
||||||
:foreach Script in=([ /system/script/find where name="global-config-overlay" ], \
|
:foreach Script in=([ /system/script/find where name="global-config-overlay" ], \
|
||||||
[ /system/script/find where name~"^global-config-overlay.d/" ]) do={
|
[ /system/script/find where name~"^global-config-overlay.d/" ]) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/system/script/run $Script;
|
/system/script/run $Script;
|
||||||
} on-error={
|
} do={
|
||||||
:log error ("Loading configuration from overlay or snippet " . \
|
:log error ("Loading configuration from overlay or snippet " . \
|
||||||
[ /system/script/get $Script name ] . " failed!");
|
[ /system/script/get $Script name ] . " failed: " . $Err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# signal we are ready
|
||||||
|
:set GlobalConfigReady true;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# Git commit id & info, expected configuration version
|
# Git commit id & info, expected configuration version
|
||||||
:global CommitId "unknown";
|
:global CommitId "unknown";
|
||||||
:global CommitInfo "unknown";
|
:global CommitInfo "unknown";
|
||||||
:global ExpectedConfigVersion 134;
|
:global ExpectedConfigVersion 138;
|
||||||
|
|
||||||
# global variables not to be changed by user
|
# global variables not to be changed by user
|
||||||
:global GlobalFunctionsReady false;
|
:global GlobalFunctionsReady false;
|
||||||
|
@ -38,6 +38,8 @@
|
||||||
:global ExitError;
|
:global ExitError;
|
||||||
:global FetchHuge;
|
:global FetchHuge;
|
||||||
:global FetchUserAgentStr;
|
:global FetchUserAgentStr;
|
||||||
|
:global FileExists;
|
||||||
|
:global FileGet;
|
||||||
:global FormatLine;
|
:global FormatLine;
|
||||||
:global FormatMultiLines;
|
:global FormatMultiLines;
|
||||||
:global GetMacVendor;
|
:global GetMacVendor;
|
||||||
|
@ -55,6 +57,7 @@
|
||||||
:global IsTimeSync;
|
:global IsTimeSync;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global LogPrintOnce;
|
:global LogPrintOnce;
|
||||||
|
:global LogPrintVerbose;
|
||||||
:global MAX;
|
:global MAX;
|
||||||
:global MIN;
|
:global MIN;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
|
@ -118,6 +121,11 @@
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:if (([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \
|
||||||
|
[[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CommonName . "\" ] ]") ]] > 0) do={
|
||||||
|
:return true;
|
||||||
|
}
|
||||||
|
|
||||||
:if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={
|
:if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={
|
||||||
$LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available.");
|
$LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available.");
|
||||||
:if ([ $CertificateDownload $CommonName ] = false) do={
|
:if ([ $CertificateDownload $CommonName ] = false) do={
|
||||||
|
@ -166,8 +174,8 @@
|
||||||
$LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . \
|
$LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . \
|
||||||
"' from repository! Trying fallback to mkcert.org...");
|
"' from repository! Trying fallback to mkcert.org...");
|
||||||
:do {
|
:do {
|
||||||
:if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={
|
:if ([ :len [ /certificate/find where common-name="ISRG Root X1" ] ] = 0) do={
|
||||||
$LogPrint error $0 ("Downloading required certificate failed.");
|
$LogPrint error $0 ("Required certificate is not available.");
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
/tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \
|
/tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \
|
||||||
|
@ -202,12 +210,19 @@
|
||||||
|
|
||||||
# name a certificate by its common-name
|
# name a certificate by its common-name
|
||||||
:set CertificateNameByCN do={
|
:set CertificateNameByCN do={
|
||||||
:local CommonName [ :tostr $1 ];
|
:local Match [ :tostr $1 ];
|
||||||
|
|
||||||
:global CleanName;
|
:global CleanName;
|
||||||
|
:global LogPrint;
|
||||||
|
|
||||||
:local Cert [ /certificate/find where common-name=$CommonName ];
|
:local Cert ([ /certificate/find where (common-name=$Match or fingerprint=$Match or name=$Match) ]->0);
|
||||||
|
:if ([ :len $Cert ] = 0) do={
|
||||||
|
$LogPrint warning $0 ("No matching certificate found.");
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
:local CommonName [ /certificate/get $Cert common-name ];
|
||||||
/certificate/set $Cert name=[ $CleanName $CommonName ];
|
/certificate/set $Cert name=[ $CleanName $CommonName ];
|
||||||
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
# multiply given character(s)
|
# multiply given character(s)
|
||||||
|
@ -309,16 +324,19 @@
|
||||||
([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \
|
([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \
|
||||||
[ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \
|
[ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \
|
||||||
([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \
|
([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \
|
||||||
[ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \
|
"Hardware:\n" . \
|
||||||
[ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \
|
[ $FormatLine " Board" ($Resource->"board-name") ] . "\n" . \
|
||||||
|
[ $FormatLine " Arch" ($Resource->"architecture-name") ] . "\n" . \
|
||||||
[ $IfThenElse ($RouterBoard->"routerboard" = true) \
|
[ $IfThenElse ($RouterBoard->"routerboard" = true) \
|
||||||
([ $FormatLine "Model" ($RouterBoard->"model") ] . \
|
([ $FormatLine " Model" ($RouterBoard->"model") ] . \
|
||||||
[ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \
|
[ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \
|
||||||
(" " . $RouterBoard->"revision") ] . "\n" . \
|
(" " . $RouterBoard->"revision") ] . "\n" . \
|
||||||
[ $FormatLine "Serial number" ($RouterBoard->"serial-number") ] . "\n") ] . \
|
[ $FormatLine " Serial" ($RouterBoard->"serial-number") ] . "\n") ] . \
|
||||||
[ $IfThenElse ([ :len ($License->"level") ] > 0) \
|
[ $IfThenElse ([ :len ($License->"nlevel") ] > 0) \
|
||||||
([ $FormatLine "License" ($License->"level") ] . "\n") ] . \
|
([ $FormatLine " License" ("level " . ($License->"nlevel")) ] . "\n") ] . \
|
||||||
"RouterOS:\n" . \
|
"RouterOS:\n" . \
|
||||||
|
[ $IfThenElse ([ :len ($License->"level") ] > 0) \
|
||||||
|
([ $FormatLine " License" ("level " . ($License->"level")) ] . "\n") ] . \
|
||||||
[ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \
|
[ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \
|
||||||
[ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \
|
[ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \
|
||||||
[ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \
|
[ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \
|
||||||
|
@ -347,6 +365,7 @@
|
||||||
|
|
||||||
:global CertificateAvailable;
|
:global CertificateAvailable;
|
||||||
:global CleanFilePath;
|
:global CleanFilePath;
|
||||||
|
:global FileExists;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global MkDir;
|
:global MkDir;
|
||||||
:global RmFile;
|
:global RmFile;
|
||||||
|
@ -367,7 +386,7 @@
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={
|
:if ([ $FileExists $PkgDest "package" ] = true) do={
|
||||||
$LogPrint info $0 ("Package file " . $PkgName . " already exists.");
|
$LogPrint info $0 ("Package file " . $PkgName . " already exists.");
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
|
@ -380,25 +399,22 @@
|
||||||
:local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile);
|
:local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile);
|
||||||
$LogPrint info $0 ("Downloading package file '" . $PkgName . "'...");
|
$LogPrint info $0 ("Downloading package file '" . $PkgName . "'...");
|
||||||
$LogPrint debug $0 ("... from url: " . $Url);
|
$LogPrint debug $0 ("... from url: " . $Url);
|
||||||
:local Retry 3;
|
|
||||||
:while ($Retry > 0) do={
|
|
||||||
:do {
|
|
||||||
/tool/fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest;
|
|
||||||
$WaitForFile $PkgDest;
|
|
||||||
|
|
||||||
:if ([ /file/get [ find where name=$PkgDest ] type ] = "package") do={
|
:onerror Err {
|
||||||
:return true;
|
/tool/fetch check-certificate=yes-without-crl $Url dst-path=$PkgDest;
|
||||||
}
|
$WaitForFile $PkgDest;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint debug $0 ("Downloading package file failed.");
|
$LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed: " . $Err);
|
||||||
}
|
:return false;
|
||||||
|
|
||||||
$RmFile $PkgDest;
|
|
||||||
:set Retry ($Retry - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed.");
|
:if ([ $FileExists $PkgDest "package" ] = false) do={
|
||||||
:return false;
|
$LogPrint warning $0 ("Downloaded file is not a package, removing.");
|
||||||
|
$RmFile $PkgDest;
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
# return either first (if "true") or second
|
# return either first (if "true") or second
|
||||||
|
@ -441,13 +457,15 @@
|
||||||
:set ExitError do={
|
:set ExitError do={
|
||||||
:local ExitOK [ :tostr $1 ];
|
:local ExitOK [ :tostr $1 ];
|
||||||
:local Name [ :tostr $2 ];
|
:local Name [ :tostr $2 ];
|
||||||
|
:local Error [ :tostr $3 ];
|
||||||
|
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
|
||||||
:if ($ExitOK = "false") do={
|
:if ($ExitOK = "false") do={
|
||||||
$LogPrint error $Name ([ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \
|
$LogPrint error $Name ([ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \
|
||||||
"Function" "Script" ] . " '" . $Name . "' exited with error.");
|
"Function" "Script" ] . " '" . $Name . "' exited with error" . \
|
||||||
|
[ $IfThenElse (!($Error ~ "^(|true|false)\$")) (": " . $Error) "." ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,14 +494,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:local FileName ($DirName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]);
|
:local FileName ($DirName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]);
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \
|
/tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \
|
||||||
http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value;
|
http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value;
|
||||||
} on-error={
|
} do={
|
||||||
:if ([ $WaitForFile $FileName 500ms ] = true) do={
|
:if ([ $WaitForFile $FileName 500ms ] = true) do={
|
||||||
$RmFile $FileName;
|
$RmFile $FileName;
|
||||||
}
|
}
|
||||||
$LogPrint debug $0 ("Failed downloading from: " . $Url);
|
$LogPrint debug $0 ("Failed downloading from " . $Url . " - " . $Err);
|
||||||
$RmDir $DirName;
|
$RmDir $DirName;
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
@ -514,6 +532,47 @@
|
||||||
$Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)");
|
$Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# check for existence of file, optionally with type
|
||||||
|
:set FileExists do={
|
||||||
|
:local FileName [ :tostr $1 ];
|
||||||
|
:local Type [ :tostr $2 ];
|
||||||
|
|
||||||
|
:global FileGet;
|
||||||
|
|
||||||
|
:local FileVal [ $FileGet $FileName ];
|
||||||
|
:if ($FileVal = false) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($FileVal->"size") ] = 0) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len $Type ] = 0 || $FileVal->"type" = $Type) do={
|
||||||
|
:return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
# get file properties in array, or false on error
|
||||||
|
:set FileGet do={
|
||||||
|
:local FileName [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global WaitForFile;
|
||||||
|
|
||||||
|
:if ([ $WaitForFile $FileName 0s ] = false) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local FileVal false;
|
||||||
|
:do {
|
||||||
|
:set FileVal [ /file/get $FileName ];
|
||||||
|
} on-error={ }
|
||||||
|
|
||||||
|
:return $FileVal;
|
||||||
|
}
|
||||||
|
|
||||||
# format a line for output
|
# format a line for output
|
||||||
:set FormatLine do={
|
:set FormatLine do={
|
||||||
:local Key [ :tostr $1 ];
|
:local Key [ :tostr $1 ];
|
||||||
|
@ -576,12 +635,12 @@
|
||||||
("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data");
|
("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data");
|
||||||
:return $Vendor;
|
:return $Vendor;
|
||||||
} on-error={
|
} on-error={
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \
|
/tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \
|
||||||
output=none as-value;
|
output=none as-value;
|
||||||
$LogPrint debug $0 ("The mac vendor is not known in database.");
|
$LogPrint debug $0 ("The mac vendor is not known in database.");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Failed getting mac vendor.");
|
$LogPrint warning $0 ("Failed getting mac vendor: " . $Err);
|
||||||
}
|
}
|
||||||
:return "unknown vendor";
|
:return "unknown vendor";
|
||||||
}
|
}
|
||||||
|
@ -845,6 +904,9 @@
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The function $LogPrintVerbose is declared, but has no code, intentionally.
|
||||||
|
# https://rsc.eworm.de/DEBUG.md#verbose-output
|
||||||
|
|
||||||
# get max value
|
# get max value
|
||||||
:set MAX do={
|
:set MAX do={
|
||||||
:if ($1 > $2) do={ :return $1; }
|
:if ($1 > $2) do={ :return $1; }
|
||||||
|
@ -862,6 +924,7 @@
|
||||||
:local Path [ :tostr $1 ];
|
:local Path [ :tostr $1 ];
|
||||||
|
|
||||||
:global CleanFilePath;
|
:global CleanFilePath;
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global RmDir;
|
:global RmDir;
|
||||||
:global WaitForFile;
|
:global WaitForFile;
|
||||||
|
@ -881,11 +944,11 @@
|
||||||
|
|
||||||
$LogPrint info $0 ("Creating disk of type tmpfs.");
|
$LogPrint info $0 ("Creating disk of type tmpfs.");
|
||||||
$RmDir "tmpfs";
|
$RmDir "tmpfs";
|
||||||
:do {
|
:onerror Err {
|
||||||
/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);
|
/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);
|
||||||
$WaitForFile "tmpfs";
|
$WaitForFile "tmpfs";
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Creating disk of type tmpfs failed!");
|
$LogPrint warning $0 ("Creating disk of type tmpfs failed: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
:return true;
|
:return true;
|
||||||
|
@ -899,7 +962,8 @@
|
||||||
|
|
||||||
$LogPrint debug $0 ("Making directory: " . $Path);
|
$LogPrint debug $0 ("Making directory: " . $Path);
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={
|
:local PathVal [ $FileGet $Path ];
|
||||||
|
:if ($PathVal->"type" = "directory") do={
|
||||||
$LogPrint debug $0 ("... which already exists.");
|
$LogPrint debug $0 ("... which already exists.");
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
|
@ -910,11 +974,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/file/add type="directory" name=$Path;
|
/file/add type="directory" name=$Path;
|
||||||
$WaitForFile $Path;
|
$WaitForFile $Path;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Making directory '" . $Path . "' failed!");
|
$LogPrint warning $0 ("Making directory '" . $Path . "' failed: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,25 +1088,26 @@
|
||||||
:set RmDir do={
|
:set RmDir do={
|
||||||
:local DirName [ :tostr $1 ];
|
:local DirName [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
|
||||||
$LogPrint debug $0 ("Removing directory: ". $DirName);
|
$LogPrint debug $0 ("Removing directory: ". $DirName);
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$DirName type!=directory ] ] > 0) do={
|
:local DirVal [ $FileGet $DirName ];
|
||||||
$LogPrint error $0 ("Directory '" . $DirName . "' is not a directory.");
|
:if ($DirVal = false) do={
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local Dir [ /file/find where name=$DirName type=directory ];
|
|
||||||
:if ([ :len $Dir ] = 0) do={
|
|
||||||
$LogPrint debug $0 ("... which does not exist.");
|
$LogPrint debug $0 ("... which does not exist.");
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:if ($DirVal->"type" != "directory") do={
|
||||||
/file/remove $Dir;
|
$LogPrint error $0 ("Directory '" . $DirName . "' is not a directory.");
|
||||||
} on-error={
|
:return false;
|
||||||
$LogPrint error $0 ("Removing directory '" . $DirName . "' (" . $Dir . ") failed.");
|
}
|
||||||
|
|
||||||
|
:onerror Err {
|
||||||
|
/file/remove $DirName;
|
||||||
|
} do={
|
||||||
|
$LogPrint error $0 ("Removing directory '" . $DirName . "' failed: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
:return true;
|
:return true;
|
||||||
|
@ -1052,25 +1117,26 @@
|
||||||
:set RmFile do={
|
:set RmFile do={
|
||||||
:local FileName [ :tostr $1 ];
|
:local FileName [ :tostr $1 ];
|
||||||
|
|
||||||
|
:global FileGet;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
|
||||||
$LogPrint debug $0 ("Removing file: ". $FileName);
|
$LogPrint debug $0 ("Removing file: ". $FileName);
|
||||||
|
|
||||||
:if ([ :len [ /file/find where name=$FileName (type=directory or type=disk) ] ] > 0) do={
|
:local FileVal [ $FileGet $FileName ];
|
||||||
$LogPrint error $0 ("File '" . $FileName . "' is not a file.");
|
:if ($FileVal = false) do={
|
||||||
:return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
:local File [ /file/find where name=$FileName !(type=directory or type=disk) ];
|
|
||||||
:if ([ :len $File ] = 0) do={
|
|
||||||
$LogPrint debug $0 ("... which does not exist.");
|
$LogPrint debug $0 ("... which does not exist.");
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:if ($FileVal->"type" = "directory" || $FileVal->"type" = "disk") do={
|
||||||
/file/remove $File;
|
$LogPrint error $0 ("File '" . $FileName . "' is not a file.");
|
||||||
} on-error={
|
:return false;
|
||||||
$LogPrint error $0 ("Removing file '" . $FileName . "' (" . $File . ") failed.");
|
}
|
||||||
|
|
||||||
|
:onerror Err {
|
||||||
|
/file/remove $FileName;
|
||||||
|
} do={
|
||||||
|
$LogPrint error $0 ("Removing file '" . $FileName . "' failed: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
:return true;
|
:return true;
|
||||||
|
@ -1103,13 +1169,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# install new scripts, update existing scripts
|
# install new scripts, update existing scripts
|
||||||
:set ScriptInstallUpdate do={ :do {
|
:set ScriptInstallUpdate do={ :onerror Err {
|
||||||
:local Scripts [ :toarray $1 ];
|
:local Scripts [ :toarray $1 ];
|
||||||
:local NewComment [ :tostr $2 ];
|
:local NewComment [ :tostr $2 ];
|
||||||
|
|
||||||
:global CommitId;
|
:global CommitId;
|
||||||
:global CommitInfo;
|
:global CommitInfo;
|
||||||
:global ExpectedConfigVersion;
|
:global ExpectedConfigVersion;
|
||||||
|
:global GlobalConfigReady;
|
||||||
|
:global GlobalFunctionsReady;
|
||||||
:global Identity;
|
:global Identity;
|
||||||
:global IDonate;
|
:global IDonate;
|
||||||
:global NoNewsAndChangesNotification;
|
:global NoNewsAndChangesNotification;
|
||||||
|
@ -1143,10 +1211,17 @@
|
||||||
|
|
||||||
:local CommitIdBefore $CommitId;
|
:local CommitIdBefore $CommitId;
|
||||||
:local ExpectedConfigVersionBefore $ExpectedConfigVersion;
|
:local ExpectedConfigVersionBefore $ExpectedConfigVersion;
|
||||||
:local ReloadGlobalFunctions false;
|
:local ReloadGlobal false;
|
||||||
:local ReloadGlobalConfig false;
|
|
||||||
:local DeviceMode [ /system/device-mode/get ];
|
:local DeviceMode [ /system/device-mode/get ];
|
||||||
|
|
||||||
|
:local CheckSums ({});
|
||||||
|
:do {
|
||||||
|
:local Url ($ScriptUpdatesBaseUrl . "checksums.json" . $ScriptUpdatesUrlSuffix);
|
||||||
|
$LogPrint debug $0 ("Fetching checksums from url: " . $Url);
|
||||||
|
:set CheckSums [ :deserialize from=json ([ /tool/fetch check-certificate=yes-without-crl \
|
||||||
|
http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]->"data") ];
|
||||||
|
} on-error={ }
|
||||||
|
|
||||||
:foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={
|
:foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={
|
||||||
:local ScriptVal [ /system/script/get $Script ];
|
:local ScriptVal [ /system/script/get $Script ];
|
||||||
:local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ];
|
:local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ];
|
||||||
|
@ -1160,8 +1235,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:if (!($ScriptInfo->"ignore" = true)) do={
|
:do {
|
||||||
:do {
|
:if ($ScriptInfo->"ignore" = true) do={
|
||||||
|
$LogPrint debug $0 ("Ignoring script '" . $ScriptVal->"name" . "', as requested.");
|
||||||
|
:error true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local CheckSum ($CheckSums->($ScriptVal->"name"));
|
||||||
|
:if ([ :len ($ScriptInfo->"base-url") ] = 0 && [ :len ($ScriptInfo->"url-suffix") ] = 0 && \
|
||||||
|
[ :convert transform=md5 to=hex [ :tolf ($ScriptVal->"source") ] ] = $CheckSum) do={
|
||||||
|
$LogPrint debug $0 ("Checksum for script '" . $ScriptVal->"name" . "' matches, ignoring.");
|
||||||
|
:error true;
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ([ :len ($ScriptInfo->"certificate") ] > 0) do={
|
||||||
|
:if ([ $CertificateAvailable ($ScriptInfo->"certificate") ] = false) do={
|
||||||
|
$LogPrint warning $0 ("Downloading certificate failed, trying without.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:onerror Err {
|
||||||
:local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ];
|
:local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ];
|
||||||
:local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ];
|
:local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ];
|
||||||
:local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix);
|
:local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix);
|
||||||
|
@ -1171,18 +1264,15 @@
|
||||||
:if ($Result->"status" = "finished") do={
|
:if ($Result->"status" = "finished") do={
|
||||||
:set SourceNew [ :tolf ($Result->"data") ];
|
:set SourceNew [ :tolf ($Result->"data") ];
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
|
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "': " . $Err);
|
||||||
:if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={
|
:if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={
|
||||||
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \
|
$LogPrint warning $0 ("Removing dummy. Typo on installation?");
|
||||||
"', removing dummy. Typo on installation?");
|
|
||||||
/system/script/remove $Script;
|
/system/script/remove $Script;
|
||||||
} else={
|
|
||||||
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!");
|
|
||||||
}
|
}
|
||||||
|
:error false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
:do {
|
|
||||||
:if ([ :len $SourceNew ] = 0) do={
|
:if ([ :len $SourceNew ] = 0) do={
|
||||||
$LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'.");
|
$LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'.");
|
||||||
:error false;
|
:error false;
|
||||||
|
@ -1228,31 +1318,25 @@
|
||||||
$LogPrint info $0 ("Updating script: " . $ScriptVal->"name");
|
$LogPrint info $0 ("Updating script: " . $ScriptVal->"name");
|
||||||
/system/script/set owner=($ScriptVal->"name") \
|
/system/script/set owner=($ScriptVal->"name") \
|
||||||
source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script;
|
source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script;
|
||||||
:if ($ScriptVal->"name" = "global-config") do={
|
:if ($ScriptVal->"name" = "global-config" || \
|
||||||
:set ReloadGlobalConfig true;
|
$ScriptVal->"name" = "global-functions" || \
|
||||||
}
|
$ScriptVal->"name" ~ ("^mod/.")) do={
|
||||||
:if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={
|
:set ReloadGlobal true;
|
||||||
:set ReloadGlobalFunctions true;
|
|
||||||
}
|
}
|
||||||
} on-error={ }
|
} on-error={ }
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ($ReloadGlobalFunctions = true) do={
|
:if ($ReloadGlobal = true) do={
|
||||||
$LogPrint info $0 ("Reloading global functions.");
|
$LogPrint info $0 ("Reloading global configuration and functions.");
|
||||||
:do {
|
:set GlobalConfigReady false;
|
||||||
/system/script/run global-functions;
|
:set GlobalFunctionsReady false;
|
||||||
} on-error={
|
:delay 1s;
|
||||||
$LogPrint error $0 ("Reloading global functions failed!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:if ($ReloadGlobalConfig = true) do={
|
:onerror Err {
|
||||||
$LogPrint info $0 ("Reloading global configuration.");
|
|
||||||
:do {
|
|
||||||
/system/script/run global-config;
|
/system/script/run global-config;
|
||||||
} on-error={
|
/system/script/run global-functions;
|
||||||
$LogPrint error $0 ("Reloading global configuration failed!" . \
|
} do={
|
||||||
" Syntax error or missing overlay?");
|
$LogPrint error $0 ("Reloading global configuration and functions failed! " . $Err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1271,7 +1355,7 @@
|
||||||
:global GlobalConfigMigration;
|
:global GlobalConfigMigration;
|
||||||
:local ChangeLogCode;
|
:local ChangeLogCode;
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix);
|
:local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix);
|
||||||
$LogPrint debug $0 ("Fetching news, changes and migration: " . $Url);
|
$LogPrint debug $0 ("Fetching news, changes and migration: " . $Url);
|
||||||
:local Result [ /tool/fetch check-certificate=yes-without-crl \
|
:local Result [ /tool/fetch check-certificate=yes-without-crl \
|
||||||
|
@ -1279,16 +1363,16 @@
|
||||||
:if ($Result->"status" = "finished") do={
|
:if ($Result->"status" = "finished") do={
|
||||||
:set ChangeLogCode ($Result->"data");
|
:set ChangeLogCode ($Result->"data");
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Failed fetching news, changes and migration!");
|
$LogPrint warning $0 ("Failed fetching news, changes and migration: " . $Err);
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :len $ChangeLogCode ] > 0) do={
|
:if ([ :len $ChangeLogCode ] > 0) do={
|
||||||
:if ([ $ValidateSyntax $ChangeLogCode ] = true) do={
|
:if ([ $ValidateSyntax $ChangeLogCode ] = true) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
[ :parse $ChangeLogCode ];
|
[ :parse $ChangeLogCode ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("The changelog failed to run!");
|
$LogPrint warning $0 ("The changelog failed to run: " . $Err);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
$LogPrint warning $0 ("The changelog failed syntax validation!");
|
$LogPrint warning $0 ("The changelog failed syntax validation!");
|
||||||
|
@ -1310,10 +1394,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration);
|
$LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration);
|
||||||
:do {
|
:onerror Err {
|
||||||
[ :parse $Migration ];
|
[ :parse $Migration ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Migration code for change " . $I . " failed to run!");
|
$LogPrint warning $0 ("Migration code for change " . $I . " failed to run: " . $Err);
|
||||||
}
|
}
|
||||||
} on-error={ }
|
} on-error={ }
|
||||||
}
|
}
|
||||||
|
@ -1355,14 +1439,14 @@
|
||||||
:set GlobalConfigChanges;
|
:set GlobalConfigChanges;
|
||||||
:set GlobalConfigMigration;
|
:set GlobalConfigMigration;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# lock script against multiple invocation
|
# lock script against multiple invocation
|
||||||
:set ScriptLock do={
|
:set ScriptLock do={
|
||||||
:local Script [ :tostr $1 ];
|
:local Script [ :tostr $1 ];
|
||||||
:local WaitMax ([ :tonum $3 ] * 10);
|
:local WaitMax [ :totime $2 ];
|
||||||
|
|
||||||
:global GetRandom20CharAlNum;
|
:global GetRandom20CharAlNum;
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
|
@ -1451,6 +1535,10 @@
|
||||||
:set ($ScriptLockOrder->$Script) ({});
|
:set ($ScriptLockOrder->$Script) ({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:if ([ :typeof $WaitMax ] = "nil" ) do={
|
||||||
|
:set WaitMax 0s;
|
||||||
|
}
|
||||||
|
|
||||||
:if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={
|
:if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={
|
||||||
$LogPrint error $0 ("A script named '" . $Script . "' does not exist!");
|
$LogPrint error $0 ("A script named '" . $Script . "' does not exist!");
|
||||||
:error false;
|
:error false;
|
||||||
|
@ -1470,12 +1558,13 @@
|
||||||
:local MyTicket [ $GetRandom20CharAlNum 6 ];
|
:local MyTicket [ $GetRandom20CharAlNum 6 ];
|
||||||
$AddTicket $Script $MyTicket;
|
$AddTicket $Script $MyTicket;
|
||||||
|
|
||||||
:local WaitCount 0;
|
:local WaitInterval ($WaitMax / 20);
|
||||||
:while ($WaitMax > $WaitCount && \
|
:local WaitTime $WaitMax;
|
||||||
|
:while ($WaitTime > 0 && \
|
||||||
([ $IsFirstTicket $Script $MyTicket ] = false || \
|
([ $IsFirstTicket $Script $MyTicket ] = false || \
|
||||||
[ $TicketCount $Script ] < [ $JobCount $Script ])) do={
|
[ $TicketCount $Script ] < [ $JobCount $Script ])) do={
|
||||||
:set WaitCount ($WaitCount + 1);
|
:set WaitTime ($WaitTime - $WaitInterval);
|
||||||
:delay 100ms;
|
:delay $WaitInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ $IsFirstTicket $Script $MyTicket ] = true && \
|
:if ([ $IsFirstTicket $Script $MyTicket ] = true && \
|
||||||
|
@ -1487,17 +1576,17 @@
|
||||||
|
|
||||||
$RemoveTicket $Script $MyTicket;
|
$RemoveTicket $Script $MyTicket;
|
||||||
$LogPrint debug $0 ("Script '" . $Script . "' started more than once" . \
|
$LogPrint debug $0 ("Script '" . $Script . "' started more than once" . \
|
||||||
[ $IfThenElse ($WaitCount > 0) " and timed out waiting for lock" "" ] . "...");
|
[ $IfThenElse ($WaitTime < $WaitMax) " and timed out waiting for lock" "" ] . "...");
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
# send notification via NotificationFunctions - expects at least two string arguments
|
# send notification via NotificationFunctions - expects at least two string arguments
|
||||||
:set SendNotification do={ :do {
|
:set SendNotification do={ :onerror Err {
|
||||||
:global SendNotification2;
|
:global SendNotification2;
|
||||||
|
|
||||||
$SendNotification2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
$SendNotification2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via NotificationFunctions - expects one array argument
|
# send notification via NotificationFunctions - expects one array argument
|
||||||
|
@ -1616,9 +1705,12 @@
|
||||||
:set ValidateSyntax do={
|
:set ValidateSyntax do={
|
||||||
:local Code [ :tostr $1 ];
|
:local Code [ :tostr $1 ];
|
||||||
|
|
||||||
:do {
|
:global LogPrint;
|
||||||
|
|
||||||
|
:onerror Err {
|
||||||
[ :parse (":local Validate do={\n" . $Code . "\n}") ];
|
[ :parse (":local Validate do={\n" . $Code . "\n}") ];
|
||||||
} on-error={
|
} do={
|
||||||
|
$LogPrint debug $0 ("Valdation failed: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
:return true;
|
:return true;
|
||||||
|
@ -1685,15 +1777,16 @@
|
||||||
:global MAX;
|
:global MAX;
|
||||||
|
|
||||||
:set FileName [ $CleanFilePath $FileName ];
|
:set FileName [ $CleanFilePath $FileName ];
|
||||||
:local I 1;
|
:local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 9);
|
||||||
:local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10);
|
|
||||||
|
|
||||||
:while ([ :len [ /file/find where name=$FileName ] ] = 0) do={
|
:do {
|
||||||
:if ($I >= 10) do={
|
:retry {
|
||||||
:return false;
|
:if ([ :len [ /file/find where name=$FileName ] ] = 0) do={
|
||||||
}
|
:error false;
|
||||||
:delay $Delay;
|
}
|
||||||
:set I ($I + 1);
|
} delay=$Delay max=10;
|
||||||
|
} on-error={
|
||||||
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:while ([ :len [ /file/find where name=$FileName ] ] > 0) do={
|
:while ([ :len [ /file/find where name=$FileName ] ] > 0) do={
|
||||||
|
@ -1732,10 +1825,10 @@
|
||||||
:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={
|
:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={
|
||||||
:local ScriptVal [ /system/script/get $Script ];
|
:local ScriptVal [ /system/script/get $Script ];
|
||||||
:if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={
|
:if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/system/script/run $Script;
|
/system/script/run $Script;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.");
|
$LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run: " . $Err);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
$LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.");
|
$LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.");
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
# wait for global-functions to finish
|
# wait for global-functions to finish
|
||||||
# https://rsc.eworm.de/doc/global-wait.md
|
# https://rsc.eworm.de/doc/global-wait.md
|
||||||
|
|
||||||
|
:global GlobalConfigReady;
|
||||||
:global GlobalFunctionsReady;
|
:global GlobalFunctionsReady;
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
:while ($GlobalConfigReady != true || $GlobalFunctionsReady != true) do={ :delay 500ms; }
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# track gps data by sending json data to http server
|
# track gps data by sending json data to http server
|
||||||
# https://rsc.eworm.de/doc/gps-track.md
|
# https://rsc.eworm.de/doc/gps-track.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global GpsTrackUrl;
|
:global GpsTrackUrl;
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
:local Gps [ /system/gps/monitor once as-value ];
|
:local Gps [ /system/gps/monitor once as-value ];
|
||||||
|
|
||||||
:if ($Gps->"valid" = true) do={
|
:if ($Gps->"valid" = true) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
http-header-field=({ [ $FetchUserAgentStr $ScriptName ]; "Content-Type: application/json" }) \
|
http-header-field=({ [ $FetchUserAgentStr $ScriptName ]; "Content-Type: application/json" }) \
|
||||||
http-data=[ :serialize to=json { "identity"=$Identity; \
|
http-data=[ :serialize to=json { "identity"=$Identity; \
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
$LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \
|
$LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \
|
||||||
"lat: " . ($Gps->"latitude") . " " . \
|
"lat: " . ($Gps->"latitude") . " " . \
|
||||||
"lon: " . ($Gps->"longitude"));
|
"lon: " . ($Gps->"longitude"));
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $ScriptName ("Failed sending GPS data!");
|
$LogPrint warning $ScriptName ("Failed sending GPS data: " . $Err);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
$LogPrint debug $ScriptName ("GPS data not valid.");
|
$LogPrint debug $ScriptName ("GPS data not valid.");
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -75,6 +75,6 @@
|
||||||
/ip/dhcp-server/lease/remove $Lease;
|
/ip/dhcp-server/lease/remove $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -82,6 +82,6 @@
|
||||||
/ip/dhcp-server/lease/remove $Lease;
|
/ip/dhcp-server/lease/remove $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -75,6 +75,6 @@
|
||||||
/ip/dhcp-server/lease/remove $Lease;
|
/ip/dhcp-server/lease/remove $Lease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -100,6 +100,6 @@
|
||||||
|
|
||||||
:delay 2s;
|
:delay 2s;
|
||||||
/caps-man/access-list/set $Entry action=accept;
|
/caps-man/access-list/set $Entry action=accept;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
# !! This is just a template to generate the real script!
|
# !! This is just a template to generate the real script!
|
||||||
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
# !! Pattern '%TEMPL%' is replaced, paths are filtered.
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -120,6 +120,6 @@
|
||||||
:delay 2s;
|
:delay 2s;
|
||||||
/caps-man/access-list/set $Entry action=accept;
|
/caps-man/access-list/set $Entry action=accept;
|
||||||
/interface/wifi/access-list/set $Entry action=accept;
|
/interface/wifi/access-list/set $Entry action=accept;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#
|
#
|
||||||
# !! Do not edit this file, it is generated from template!
|
# !! Do not edit this file, it is generated from template!
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
@ -97,6 +97,6 @@
|
||||||
|
|
||||||
:delay 2s;
|
:delay 2s;
|
||||||
/interface/wifi/access-list/set $Entry action=accept;
|
/interface/wifi/access-list/set $Entry action=accept;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# and add/remove/update DNS entries from IPSec mode-config
|
# and add/remove/update DNS entries from IPSec mode-config
|
||||||
# https://rsc.eworm.de/doc/ipsec-to-dns.md
|
# https://rsc.eworm.de/doc/ipsec-to-dns.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Domain;
|
:global Domain;
|
||||||
|
@ -79,6 +79,6 @@
|
||||||
/ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
/ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# update firewall and dns settings on IPv6 prefix change
|
# update firewall and dns settings on IPv6 prefix change
|
||||||
# https://rsc.eworm.de/doc/ipv6-update.md
|
# https://rsc.eworm.de/doc/ipv6-update.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -20,7 +20,9 @@
|
||||||
:global ScriptLock;
|
:global ScriptLock;
|
||||||
|
|
||||||
:local NaAddress $"na-address";
|
:local NaAddress $"na-address";
|
||||||
|
:local NaValid $"na-valid";
|
||||||
:local PdPrefix $"pd-prefix";
|
:local PdPrefix $"pd-prefix";
|
||||||
|
:local PdValid $"pd-valid";
|
||||||
|
|
||||||
:if ([ $ScriptLock $ScriptName ] = false) do={
|
:if ([ $ScriptLock $ScriptName ] = false) do={
|
||||||
:set ExitOK true;
|
:set ExitOK true;
|
||||||
|
@ -33,12 +35,18 @@
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ([ :typeof $PdPrefix ] = "nothing") do={
|
:if ([ :typeof $PdPrefix ] = "nothing" || [ :typeof $PdValid ] = "nothing") do={
|
||||||
$LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client.");
|
$LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client.");
|
||||||
:set ExitOK true;
|
:set ExitOK true;
|
||||||
:error false;
|
:error false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:if ($PdValid != 1) do={
|
||||||
|
$LogPrint info $ScriptName ("The prefix " . $PdPrefix . " is no longer valid. Ignoring.");
|
||||||
|
:set ExitOK true;
|
||||||
|
:error false;
|
||||||
|
}
|
||||||
|
|
||||||
:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ];
|
:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ];
|
||||||
:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={
|
: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) dynamic=yes;
|
/ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool) dynamic=yes;
|
||||||
|
@ -94,6 +102,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# run scripts on DHCP lease
|
# run scripts on DHCP lease
|
||||||
# https://rsc.eworm.de/doc/lease-script.md
|
# https://rsc.eworm.de/doc/lease-script.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Grep;
|
:global Grep;
|
||||||
|
@ -53,13 +53,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:foreach Order,Script in=$RunOrder do={
|
:foreach Order,Script in=$RunOrder do={
|
||||||
:do {
|
:onerror Err {
|
||||||
$LogPrint debug $ScriptName ("Running script with order " . $Order . ": " . $Script);
|
$LogPrint debug $ScriptName ("Running script with order " . $Order . ": " . $Script);
|
||||||
/system/script/run $Script;
|
/system/script/run $Script;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $ScriptName ("Running script '" . $Script . "' failed!");
|
$LogPrint warning $ScriptName ("Running script '" . $Script . "' failed: " . $Err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# forward log messages via notification
|
# forward log messages via notification
|
||||||
# https://rsc.eworm.de/doc/log-forward.md
|
# https://rsc.eworm.de/doc/log-forward.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global Identity;
|
:global Identity;
|
||||||
|
@ -108,6 +108,6 @@
|
||||||
|
|
||||||
:local LogAll [ /log/find ];
|
:local LogAll [ /log/find ];
|
||||||
:set LogForwardLast ($LogAll->([ :len $LogAll ] - 1) );
|
:set LogForwardLast ($LogAll->([ :len $LogAll ] - 1) );
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
BIN
logo.avif
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
logo.png
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
:global BridgePortTo;
|
:global BridgePortTo;
|
||||||
|
|
||||||
:set BridgePortTo do={ :do {
|
:set BridgePortTo do={ :onerror Err {
|
||||||
:local BridgePortTo [ :tostr $1 ];
|
:local BridgePortTo [ :tostr $1 ];
|
||||||
|
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
|
@ -65,6 +65,6 @@
|
||||||
$LogPrint info $0 ("Re-enabling interfaces...");
|
$LogPrint info $0 ("Re-enabling interfaces...");
|
||||||
/interface/ethernet/enable $InterfaceReEnable;
|
/interface/ethernet/enable $InterfaceReEnable;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
:global BridgePortVlan;
|
:global BridgePortVlan;
|
||||||
|
|
||||||
:global BridgePortVlan do={ :do {
|
:global BridgePortVlan do={ :onerror Err {
|
||||||
:local ConfigTo [ :tostr $1 ];
|
:local ConfigTo [ :tostr $1 ];
|
||||||
|
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
|
@ -74,6 +74,6 @@
|
||||||
$LogPrint info $0 ("Re-enabling interfaces...");
|
$LogPrint info $0 ("Re-enabling interfaces...");
|
||||||
/interface/ethernet/enable $InterfaceReEnable;
|
/interface/ethernet/enable $InterfaceReEnable;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
:global InspectVarReturn;
|
:global InspectVarReturn;
|
||||||
|
|
||||||
# inspect variable and print on terminal
|
# inspect variable and print on terminal
|
||||||
:set InspectVar do={ :do {
|
:set InspectVar do={ :onerror Err {
|
||||||
:global InspectVarReturn;
|
:global InspectVarReturn;
|
||||||
|
|
||||||
:put [ :tocrlf [ $InspectVarReturn $1 ] ];
|
:put [ :tocrlf [ $InspectVarReturn $1 ] ];
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# inspect variable and return formatted string
|
# inspect variable and return formatted string
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
:local Input $1;
|
:local Input $1;
|
||||||
:local Level (0 + [ :tonum $2 ]);
|
:local Level (0 + [ :tonum $2 ]);
|
||||||
|
|
||||||
|
:global CharacterReplace;
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
:global InspectVarReturn;
|
:global InspectVarReturn;
|
||||||
|
|
||||||
|
@ -33,14 +34,13 @@
|
||||||
:local Value [ :tostr $2 ];
|
:local Value [ :tostr $2 ];
|
||||||
:local Level [ :tonum $3 ];
|
:local Level [ :tonum $3 ];
|
||||||
|
|
||||||
:local Indent "";
|
:global CharacterMultiply;
|
||||||
:for I from=1 to=$Level step=1 do={
|
|
||||||
:set Indent ($Indent . " ");
|
:return ([ $CharacterMultiply " " $Level ] . "-" . $Prefix . "-> " . $Value);
|
||||||
}
|
|
||||||
:return ($Indent . "-" . $Prefix . "-> " . $Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:local TypeOf [ :typeof $Input ];
|
:local TypeOf [ :typeof $Input ];
|
||||||
|
:local Len [ :len $Input ];
|
||||||
:local Return [ $IndentReturn "type" $TypeOf $Level ];
|
:local Return [ $IndentReturn "type" $TypeOf $Level ];
|
||||||
|
|
||||||
:if ($TypeOf = "array") do={
|
:if ($TypeOf = "array") do={
|
||||||
|
@ -50,6 +50,16 @@
|
||||||
[ $InspectVarReturn $Value ($Level + 2) ]);
|
[ $InspectVarReturn $Value ($Level + 2) ]);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
|
:if ($TypeOf = "str") do={
|
||||||
|
:set $Return ($Return . "\n" . \
|
||||||
|
[ $IndentReturn "len" $Len $Level ]);
|
||||||
|
:if ([ :typeof [ :find $Input ("\r") ] ] = "num") do={
|
||||||
|
:set Input [ $CharacterReplace $Input ("\r") "" ];
|
||||||
|
}
|
||||||
|
:if ([ :typeof [ :find $Input ("\n") ] ] = "num") do={
|
||||||
|
:set Input [ $CharacterReplace $Input ("\n") " " ];
|
||||||
|
}
|
||||||
|
}
|
||||||
:if ($TypeOf != "nothing") do={
|
:if ($TypeOf != "nothing") do={
|
||||||
:set $Return ($Return . "\n" . \
|
:set $Return ($Return . "\n" . \
|
||||||
[ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \
|
[ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
:global IPCalcReturn;
|
:global IPCalcReturn;
|
||||||
|
|
||||||
# print netmask, network, min host, max host and broadcast
|
# print netmask, network, min host, max host and broadcast
|
||||||
:set IPCalc do={ :do {
|
:set IPCalc do={ :onerror Err {
|
||||||
:local Input [ :tostr $1 ];
|
:local Input [ :tostr $1 ];
|
||||||
|
|
||||||
:global FormatLine;
|
:global FormatLine;
|
||||||
|
@ -27,8 +27,8 @@
|
||||||
[ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \
|
[ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \
|
||||||
[ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \
|
[ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \
|
||||||
[ $FormatLine "Broadcast" ($Values->"broadcast") ]) ];
|
[ $FormatLine "Broadcast" ($Values->"broadcast") ]) ];
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# calculate and return netmask, network, min host, max host and broadcast
|
# calculate and return netmask, network, min host, max host and broadcast
|
||||||
|
|
|
@ -35,14 +35,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# flush e-mail queue
|
# flush e-mail queue
|
||||||
:set FlushEmailQueue do={ :do {
|
:set FlushEmailQueue do={ :onerror Err {
|
||||||
:global EmailQueue;
|
:global EmailQueue;
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
:global EMailGenerateFrom;
|
:global EMailGenerateFrom;
|
||||||
|
:global FileExists;
|
||||||
:global IsDNSResolving;
|
:global IsDNSResolving;
|
||||||
:global IsTimeSync;
|
:global IsTimeSync;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
:global RmFile;
|
||||||
|
|
||||||
:local AllDone true;
|
:local AllDone true;
|
||||||
:local QueueLen [ :len $EmailQueue ];
|
:local QueueLen [ :len $EmailQueue ];
|
||||||
|
@ -89,35 +91,40 @@
|
||||||
|
|
||||||
:foreach Id,Message in=$EmailQueue do={
|
:foreach Id,Message in=$EmailQueue do={
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
:local Attach ({});
|
|
||||||
:while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; }
|
:while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; }
|
||||||
:foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={
|
:onerror Err {
|
||||||
:if ([ :len [ /file/find where name=$File ] ] = 1) do={
|
:local Attach ({});
|
||||||
:set Attach ($Attach, $File);
|
:foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={
|
||||||
} else={
|
:if ([ $FileExists $File ] = true) do={
|
||||||
$LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach.");
|
:set Attach ($Attach, $File);
|
||||||
}
|
} else={
|
||||||
}
|
$LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach.");
|
||||||
/tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \
|
|
||||||
subject=($Message->"subject") body=($Message->"body") file=$Attach;
|
|
||||||
:local Wait true;
|
|
||||||
:do {
|
|
||||||
:delay 1s;
|
|
||||||
:local Status [ /tool/e-mail/get last-status ];
|
|
||||||
:if ($Status = "succeeded") do={
|
|
||||||
:set ($EmailQueue->$Id);
|
|
||||||
:set Wait false;
|
|
||||||
:if (($Message->"remove-attach") = true) do={
|
|
||||||
:foreach File in=$Attach do={
|
|
||||||
/file/remove $File;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:if ($Status = "failed") do={
|
/tool/e-mail/send from=[ $EMailGenerateFrom ] to=($Message->"to") cc=($Message->"cc") \
|
||||||
:set AllDone false;
|
subject=($Message->"subject") body=($Message->"body") file=$Attach;
|
||||||
:set Wait false;
|
:local Wait true;
|
||||||
}
|
:do {
|
||||||
} while=($Wait = true);
|
:delay 1s;
|
||||||
|
:local Status [ /tool/e-mail/get last-status ];
|
||||||
|
:if ($Status = "succeeded") do={
|
||||||
|
:set ($EmailQueue->$Id);
|
||||||
|
:set Wait false;
|
||||||
|
:if (($Message->"remove-attach") = true) do={
|
||||||
|
:foreach File in=$Attach do={
|
||||||
|
$RmFile $File;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ($Status = "failed") do={
|
||||||
|
:set AllDone false;
|
||||||
|
:set Wait false;
|
||||||
|
}
|
||||||
|
} while=($Wait = true);
|
||||||
|
} do={
|
||||||
|
$LogPrint warning $0 ("Sending queued mail failed: " . $Err);
|
||||||
|
:set AllDone false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,8 +142,8 @@
|
||||||
|
|
||||||
/system/scheduler/set interval=(($SchedVal->"run-count") . "m") \
|
/system/scheduler/set interval=(($SchedVal->"run-count") . "m") \
|
||||||
comment="Waiting for retry..." $Scheduler;
|
comment="Waiting for retry..." $Scheduler;
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# generate filter for log-forward
|
# generate filter for log-forward
|
||||||
|
@ -176,6 +183,7 @@
|
||||||
:global IfThenElse;
|
:global IfThenElse;
|
||||||
:global NotificationEMailSignature;
|
:global NotificationEMailSignature;
|
||||||
:global NotificationEMailSubject;
|
:global NotificationEMailSubject;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
:local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
|
:local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
|
||||||
:local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];
|
:local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];
|
||||||
|
@ -188,13 +196,23 @@
|
||||||
:if ([ :typeof $EmailQueue ] = "nothing") do={
|
:if ([ :typeof $EmailQueue ] = "nothing") do={
|
||||||
:set EmailQueue ({});
|
:set EmailQueue ({});
|
||||||
}
|
}
|
||||||
|
:local Truncated false;
|
||||||
|
:local Body ($Notification->"message");
|
||||||
|
:if ([ :len $Body ] > 62000) do={
|
||||||
|
:set Body ([ :pick $Body 0 62000 ] . "...");
|
||||||
|
:set Truncated true;
|
||||||
|
}
|
||||||
:local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ];
|
:local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ];
|
||||||
|
:set Body ($Body . "\n" . \
|
||||||
|
[ $IfThenElse ([ :len ($Notification->"link") ] > 0) \
|
||||||
|
("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ] . \
|
||||||
|
[ $IfThenElse ($Truncated = true) ("\n" . [ $SymbolForNotification "scissors" ] . \
|
||||||
|
"The message was too long and has been truncated!") ] . \
|
||||||
|
[ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]);
|
||||||
:set ($EmailQueue->[ :len $EmailQueue ]) {
|
:set ($EmailQueue->[ :len $EmailQueue ]) {
|
||||||
to=$To; cc=$Cc;
|
to=$To; cc=$Cc;
|
||||||
subject=[ $NotificationEMailSubject ($Notification->"subject") ];
|
subject=[ $NotificationEMailSubject ($Notification->"subject") ];
|
||||||
body=(($Notification->"message") . \
|
body=$Body; \
|
||||||
[ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \
|
|
||||||
[ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \
|
|
||||||
attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") };
|
attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") };
|
||||||
:if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={
|
:if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={
|
||||||
/system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \
|
/system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \
|
||||||
|
@ -248,12 +266,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# send notification via e-mail - expects at least two string arguments
|
# send notification via e-mail - expects at least two string arguments
|
||||||
:set SendEMail do={ :do {
|
:set SendEMail do={ :onerror Err {
|
||||||
:global SendEMail2;
|
:global SendEMail2;
|
||||||
|
|
||||||
$SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 });
|
$SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 });
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via e-mail - expects one array argument
|
# send notification via e-mail - expects one array argument
|
||||||
|
|
139
mod/notification-gotify.rsc
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#!rsc by RouterOS
|
||||||
|
# RouterOS script: mod/notification-gotify
|
||||||
|
# Copyright (c) 2013-2025 Christian Hesse <mail@eworm.de>
|
||||||
|
# Leonardo David Monteiro <leo@cub3.xyz>
|
||||||
|
# https://rsc.eworm.de/COPYING.md
|
||||||
|
#
|
||||||
|
# requires RouterOS, version=7.15
|
||||||
|
# requires device-mode, fetch, scheduler
|
||||||
|
#
|
||||||
|
# send notifications via Gotify (gotify.net)
|
||||||
|
# https://rsc.eworm.de/doc/mod/notification-gotify.md
|
||||||
|
|
||||||
|
:global FlushGotifyQueue;
|
||||||
|
:global NotificationFunctions;
|
||||||
|
:global PurgeGotifyQueue;
|
||||||
|
:global SendGotify;
|
||||||
|
:global SendGotify2;
|
||||||
|
|
||||||
|
# flush Gotify queue
|
||||||
|
:set FlushGotifyQueue do={ :onerror Err {
|
||||||
|
:global GotifyQueue;
|
||||||
|
|
||||||
|
:global IsFullyConnected;
|
||||||
|
:global LogPrint;
|
||||||
|
|
||||||
|
:if ([ $IsFullyConnected ] = false) do={
|
||||||
|
$LogPrint debug $0 ("System is not fully connected, not flushing.");
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local AllDone true;
|
||||||
|
:local QueueLen [ :len $GotifyQueue ];
|
||||||
|
|
||||||
|
:if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] > 0 && $QueueLen = 0) do={
|
||||||
|
$LogPrint warning $0 ("Flushing Gotify messages from scheduler, but queue is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
:foreach Id,Message in=$GotifyQueue do={
|
||||||
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
|
:onerror Err {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
|
http-header-field=($Message->"headers") http-data=[ :serialize to=json ($Message->"message") ] \
|
||||||
|
($Message->"url") as-value;
|
||||||
|
:set ($GotifyQueue->$Id);
|
||||||
|
} do={
|
||||||
|
$LogPrint debug $0 ("Sending queued Gotify message failed: " . $Err);
|
||||||
|
:set AllDone false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:if ($AllDone = true && $QueueLen = [ :len $GotifyQueue ]) do={
|
||||||
|
/system/scheduler/remove [ find where name="_FlushGotifyQueue" ];
|
||||||
|
:set GotifyQueue;
|
||||||
|
}
|
||||||
|
} do={
|
||||||
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
|
} }
|
||||||
|
|
||||||
|
# send notification via Gotify - expects one array argument
|
||||||
|
:set ($NotificationFunctions->"gotify") do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global Identity;
|
||||||
|
:global IdentityExtra;
|
||||||
|
:global GotifyQueue;
|
||||||
|
:global GotifyServer;
|
||||||
|
:global GotifyServerOverride;
|
||||||
|
:global GotifyToken;
|
||||||
|
:global GotifyTokenOverride;
|
||||||
|
|
||||||
|
:global EitherOr;
|
||||||
|
:global FetchUserAgentStr;
|
||||||
|
:global IfThenElse;
|
||||||
|
:global LogPrint;
|
||||||
|
:global SymbolForNotification;
|
||||||
|
|
||||||
|
:local Server [ $EitherOr ($GotifyServerOverride->($Notification->"origin")) $GotifyServer ];
|
||||||
|
:local Token [ $EitherOr ($GotifyTokenOverride->($Notification->"origin")) $GotifyToken ];
|
||||||
|
|
||||||
|
:if ([ :len $Token ] = 0) do={
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Url ("https://" . $Server . "/message");
|
||||||
|
:local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \
|
||||||
|
("X-Gotify-Key: " . $Token); "Content-Type: application/json" });
|
||||||
|
:local Message ({
|
||||||
|
"title"=("[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")); \
|
||||||
|
"message"=(($Notification->"message") . "\n" . [ $IfThenElse ([ :len ($Notification->"link") ] > 0) \
|
||||||
|
("\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")) ]); \
|
||||||
|
"priority"=[ :tonum [ $IfThenElse ($Notification->"silent") 2 5 ] ] });
|
||||||
|
|
||||||
|
:onerror Err {
|
||||||
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
|
http-header-field=$Headers http-data=[ :serialize to=json $Message ] $Url as-value;
|
||||||
|
} do={
|
||||||
|
$LogPrint info $0 ("Failed sending Gotify notification: " . $Err . " - Queuing...");
|
||||||
|
|
||||||
|
:if ([ :typeof $GotifyQueue ] = "nothing") do={
|
||||||
|
:set GotifyQueue ({});
|
||||||
|
}
|
||||||
|
:set ($Message->"message") (($Notification->"message") . "\n" . \
|
||||||
|
[ $SymbolForNotification "alarm-clock" ] . "This message was queued since " . \
|
||||||
|
[ /system/clock/get date ] . " " . [ /system/clock/get time ] . " and may be obsolete.");
|
||||||
|
:set ($GotifyQueue->[ :len $GotifyQueue ]) \
|
||||||
|
{ url=$Url; headers=$Headers; message=$Message };
|
||||||
|
:if ([ :len [ /system/scheduler/find where name="_FlushGotifyQueue" ] ] = 0) do={
|
||||||
|
/system/scheduler/add name="_FlushGotifyQueue" interval=1m start-time=startup \
|
||||||
|
on-event=(":global FlushGotifyQueue; \$FlushGotifyQueue;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# purge the Gotify queue
|
||||||
|
:set PurgeGotifyQueue do={
|
||||||
|
:global GotifyQueue;
|
||||||
|
|
||||||
|
/system/scheduler/remove [ find where name="_FlushGotifyQueue" ];
|
||||||
|
:set GotifyQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
# send notification via Gotify - expects at least two string arguments
|
||||||
|
:set SendGotify do={ :onerror Err {
|
||||||
|
:global SendGotify2;
|
||||||
|
|
||||||
|
$SendGotify2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
||||||
|
} do={
|
||||||
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
|
} }
|
||||||
|
|
||||||
|
# send notification via Gotify - expects one array argument
|
||||||
|
:set SendGotify2 do={
|
||||||
|
:local Notification $1;
|
||||||
|
|
||||||
|
:global NotificationFunctions;
|
||||||
|
|
||||||
|
($NotificationFunctions->"gotify") ("\$NotificationFunctions->\"gotify\"") $Notification;
|
||||||
|
}
|
|
@ -19,7 +19,7 @@
|
||||||
:global SetupMatrixJoinRoom;
|
:global SetupMatrixJoinRoom;
|
||||||
|
|
||||||
# flush Matrix queue
|
# flush Matrix queue
|
||||||
:set FlushMatrixQueue do={ :do {
|
:set FlushMatrixQueue do={ :onerror Err {
|
||||||
:global MatrixQueue;
|
:global MatrixQueue;
|
||||||
|
|
||||||
:global IsFullyConnected;
|
:global IsFullyConnected;
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
:foreach Id,Message in=$MatrixQueue do={
|
:foreach Id,Message in=$MatrixQueue do={
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none \
|
/tool/fetch check-certificate=yes-without-crl output=none \
|
||||||
http-header-field=($Message->"headers") http-method=post \
|
http-header-field=($Message->"headers") http-method=post \
|
||||||
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain");
|
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain");
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \
|
("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \
|
||||||
"/send/m.room.message?access_token=" . $Message->"accesstoken") as-value;
|
"/send/m.room.message?access_token=" . $Message->"accesstoken") as-value;
|
||||||
:set ($MatrixQueue->$Id);
|
:set ($MatrixQueue->$Id);
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint debug $0 ("Sending queued Matrix message failed.");
|
$LogPrint debug $0 ("Sending queued Matrix message failed: " . $Err);
|
||||||
:set AllDone false;
|
:set AllDone false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@
|
||||||
/system/scheduler/remove [ find where name="_FlushMatrixQueue" ];
|
/system/scheduler/remove [ find where name="_FlushMatrixQueue" ];
|
||||||
:set MatrixQueue;
|
:set MatrixQueue;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via Matrix - expects one array argument
|
# send notification via Matrix - expects one array argument
|
||||||
|
@ -129,15 +129,15 @@
|
||||||
[ $PrepareText $Label ] . "</a>");
|
[ $PrepareText $Label ] . "</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none \
|
/tool/fetch check-certificate=yes-without-crl output=none \
|
||||||
http-header-field=$Headers http-method=post \
|
http-header-field=$Headers http-method=post \
|
||||||
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain;
|
http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain;
|
||||||
"format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \
|
"format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \
|
||||||
("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \
|
("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \
|
||||||
"/send/m.room.message?access_token=" . $AccessToken) as-value;
|
"/send/m.room.message?access_token=" . $AccessToken) as-value;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint info $0 ("Failed sending Matrix notification! Queuing...");
|
$LogPrint info $0 ("Failed sending Matrix notification: " . $Err . " - Queuing...");
|
||||||
|
|
||||||
:if ([ :typeof $MatrixQueue ] = "nothing") do={
|
:if ([ :typeof $MatrixQueue ] = "nothing") do={
|
||||||
:set MatrixQueue ({});
|
:set MatrixQueue ({});
|
||||||
|
@ -167,12 +167,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# send notification via Matrix - expects at least two string arguments
|
# send notification via Matrix - expects at least two string arguments
|
||||||
:set SendMatrix do={ :do {
|
:set SendMatrix do={ :onerror Err {
|
||||||
:global SendMatrix2;
|
:global SendMatrix2;
|
||||||
|
|
||||||
$SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 });
|
$SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 });
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via Matrix - expects one array argument
|
# send notification via Matrix - expects one array argument
|
||||||
|
@ -196,14 +196,14 @@
|
||||||
:global MatrixHomeServer;
|
:global MatrixHomeServer;
|
||||||
|
|
||||||
:local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ];
|
:local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ];
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
||||||
http-header-field=({ [ $FetchUserAgentStr $0 ] }) \
|
http-header-field=({ [ $FetchUserAgentStr $0 ] }) \
|
||||||
("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data");
|
("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data");
|
||||||
:set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url");
|
:set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url");
|
||||||
$LogPrint debug $0 ("Home server is: " . $MatrixHomeServer);
|
$LogPrint debug $0 ("Home server is: " . $MatrixHomeServer);
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Failed getting home server!");
|
$LogPrint error $0 ("Failed getting home server: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,27 +211,27 @@
|
||||||
:set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ];
|
:set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
||||||
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \
|
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \
|
||||||
http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \
|
http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \
|
||||||
("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data");
|
("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data");
|
||||||
:set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token");
|
:set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token");
|
||||||
$LogPrint debug $0 ("Access token is: " . $MatrixAccessToken);
|
$LogPrint debug $0 ("Access token is: " . $MatrixAccessToken);
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Failed logging in (and getting access token)!");
|
$LogPrint error $0 ("Failed logging in (and getting access token): " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ];
|
/system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ];
|
||||||
/system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \
|
/system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \
|
||||||
"# configuration snippet: mod/notification-matrix\n\n" . \
|
"# configuration snippet: mod/notification-matrix\n\n" . \
|
||||||
":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \
|
":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \
|
||||||
":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n");
|
":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n");
|
||||||
$LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!");
|
$LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Failed adding configuration snippet!");
|
$LogPrint error $0 ("Failed adding configuration snippet: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,24 +248,24 @@
|
||||||
:global MatrixHomeServer;
|
:global MatrixHomeServer;
|
||||||
:global MatrixRoom;
|
:global MatrixRoom;
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none \
|
/tool/fetch check-certificate=yes-without-crl output=none \
|
||||||
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \
|
http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \
|
||||||
("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \
|
("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \
|
||||||
"/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value;
|
"/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value;
|
||||||
$LogPrint debug $0 ("Joined the room.");
|
$LogPrint debug $0 ("Joined the room.");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Failed joining the room!");
|
$LogPrint error $0 ("Failed joining the room: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ];
|
:local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ];
|
||||||
/system/script/set $Snippet source=([ get $Snippet source ] . \
|
/system/script/set $Snippet source=([ get $Snippet source ] . \
|
||||||
":global MatrixRoom \"" . $MatrixRoom . "\";\n");
|
":global MatrixRoom \"" . $MatrixRoom . "\";\n");
|
||||||
$LogPrint info $0 ("Appended configuration to configuration snippet. Please review!");
|
$LogPrint info $0 ("Appended configuration to configuration snippet. Please review!");
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint error $0 ("Failed appending configuration to snippet!");
|
$LogPrint error $0 ("Failed appending configuration to snippet: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
:global SendNtfy2;
|
:global SendNtfy2;
|
||||||
|
|
||||||
# flush ntfy queue
|
# flush ntfy queue
|
||||||
:set FlushNtfyQueue do={ :do {
|
:set FlushNtfyQueue do={ :onerror Err {
|
||||||
:global NtfyQueue;
|
:global NtfyQueue;
|
||||||
:global NtfyMessageIDs;
|
|
||||||
|
|
||||||
:global IsFullyConnected;
|
:global IsFullyConnected;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
|
@ -37,13 +36,13 @@
|
||||||
|
|
||||||
:foreach Id,Message in=$NtfyQueue do={
|
:foreach Id,Message in=$NtfyQueue do={
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
http-header-field=($Message->"headers") http-data=($Message->"text") \
|
http-header-field=($Message->"headers") http-data=($Message->"text") \
|
||||||
($Message->"url") as-value;
|
($Message->"url") as-value;
|
||||||
:set ($NtfyQueue->$Id);
|
:set ($NtfyQueue->$Id);
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint debug $0 ("Sending queued Ntfy message failed.");
|
$LogPrint debug $0 ("Sending queued Ntfy message failed: " . $Err);
|
||||||
:set AllDone false;
|
:set AllDone false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +52,8 @@
|
||||||
/system/scheduler/remove [ find where name="_FlushNtfyQueue" ];
|
/system/scheduler/remove [ find where name="_FlushNtfyQueue" ];
|
||||||
:set NtfyQueue;
|
:set NtfyQueue;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via ntfy - expects one array argument
|
# send notification via ntfy - expects one array argument
|
||||||
|
@ -108,7 +107,7 @@
|
||||||
:set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link"));
|
:set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link"));
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
:if ($Server = "ntfy.sh") do={
|
:if ($Server = "ntfy.sh") do={
|
||||||
:if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={
|
:if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={
|
||||||
$LogPrint warning $0 ("Downloading required certificate failed.");
|
$LogPrint warning $0 ("Downloading required certificate failed.");
|
||||||
|
@ -117,8 +116,8 @@
|
||||||
}
|
}
|
||||||
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
/tool/fetch check-certificate=yes-without-crl output=none http-method=post \
|
||||||
http-header-field=$Headers http-data=$Text $Url as-value;
|
http-header-field=$Headers http-data=$Text $Url as-value;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint info $0 ("Failed sending ntfy notification! Queuing...");
|
$LogPrint info $0 ("Failed sending ntfy notification: " . $Err . " - Queuing...");
|
||||||
|
|
||||||
:if ([ :typeof $NtfyQueue ] = "nothing") do={
|
:if ([ :typeof $NtfyQueue ] = "nothing") do={
|
||||||
:set NtfyQueue ({});
|
:set NtfyQueue ({});
|
||||||
|
@ -144,12 +143,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# send notification via ntfy - expects at least two string arguments
|
# send notification via ntfy - expects at least two string arguments
|
||||||
:set SendNtfy do={ :do {
|
:set SendNtfy do={ :onerror Err {
|
||||||
:global SendNtfy2;
|
:global SendNtfy2;
|
||||||
|
|
||||||
$SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
$SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via ntfy - expects one array argument
|
# send notification via ntfy - expects one array argument
|
||||||
|
|
|
@ -10,13 +10,14 @@
|
||||||
# https://rsc.eworm.de/doc/mod/notification-telegram.md
|
# https://rsc.eworm.de/doc/mod/notification-telegram.md
|
||||||
|
|
||||||
:global FlushTelegramQueue;
|
:global FlushTelegramQueue;
|
||||||
|
:global GetTelegramChatId;
|
||||||
:global NotificationFunctions;
|
:global NotificationFunctions;
|
||||||
:global PurgeTelegramQueue;
|
:global PurgeTelegramQueue;
|
||||||
:global SendTelegram;
|
:global SendTelegram;
|
||||||
:global SendTelegram2;
|
:global SendTelegram2;
|
||||||
|
|
||||||
# flush telegram queue
|
# flush telegram queue
|
||||||
:set FlushTelegramQueue do={ :do {
|
:set FlushTelegramQueue do={ :onerror Err {
|
||||||
:global TelegramQueue;
|
:global TelegramQueue;
|
||||||
:global TelegramMessageIDs;
|
:global TelegramMessageIDs;
|
||||||
|
|
||||||
|
@ -37,14 +38,14 @@
|
||||||
|
|
||||||
:foreach Id,Message in=$TelegramQueue do={
|
:foreach Id,Message in=$TelegramQueue do={
|
||||||
:if ([ :typeof $Message ] = "array" ) do={
|
:if ([ :typeof $Message ] = "array" ) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
|
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
|
||||||
("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \
|
("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \
|
||||||
http-data=($Message->"http-data") as-value ]->"data");
|
http-data=($Message->"http-data") as-value ]->"data");
|
||||||
:set ($TelegramQueue->$Id);
|
:set ($TelegramQueue->$Id);
|
||||||
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
|
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint debug $0 ("Sending queued Telegram message failed.");
|
$LogPrint debug $0 ("Sending queued Telegram message failed: " . $Err);
|
||||||
:set AllDone false;
|
:set AllDone false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,8 +55,47 @@
|
||||||
/system/scheduler/remove [ find where name="_FlushTelegramQueue" ];
|
/system/scheduler/remove [ find where name="_FlushTelegramQueue" ];
|
||||||
:set TelegramQueue;
|
:set TelegramQueue;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
|
} }
|
||||||
|
|
||||||
|
# get the chat id
|
||||||
|
:set GetTelegramChatId do={ :onerror Err {
|
||||||
|
:global TelegramTokenId;
|
||||||
|
|
||||||
|
:global CertificateAvailable;
|
||||||
|
:global LogPrint;
|
||||||
|
|
||||||
|
:if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
|
||||||
|
$LogPrint warning $0 ("Downloading required certificate failed.");
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Data;
|
||||||
|
:onerror Err {
|
||||||
|
:set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
||||||
|
("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=0" . \
|
||||||
|
"&allowed_updates=%5B%22message%22%5D") as-value ]->"data");
|
||||||
|
} do={
|
||||||
|
$LogPrint warning $0 ("Fetching data failed: " . $Err);
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local JSON [ :deserialize from=json value=$Data ];
|
||||||
|
:local Count [ :len ($JSON->"result") ];
|
||||||
|
|
||||||
|
:if ($Count = 0) do={
|
||||||
|
$LogPrint info $0 ("No message received.");
|
||||||
|
:return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local Message ($JSON->"result"->($Count - 1)->"message");
|
||||||
|
$LogPrint info $0 ("The chat id is: " . ($Message->"chat"->"id"));
|
||||||
|
:if (($Message->"is_topic_message") = true) do={
|
||||||
|
$LogPrint info $0 ("The thread id is: " . ($Message->"message_thread_id"));
|
||||||
|
}
|
||||||
|
} do={
|
||||||
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via telegram - expects one array argument
|
# send notification via telegram - expects one array argument
|
||||||
|
@ -111,7 +151,8 @@
|
||||||
:local ChatId [ $EitherOr ($Notification->"chatid") \
|
:local ChatId [ $EitherOr ($Notification->"chatid") \
|
||||||
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
|
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
|
||||||
:local ThreadId [ $EitherOr ($Notification->"threadid") \
|
:local ThreadId [ $EitherOr ($Notification->"threadid") \
|
||||||
[ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) $TelegramThreadId ] ];
|
[ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) \
|
||||||
|
[ $IfThenElse ([ :len ($TelegramChatIdOverride->($Notification->"origin")) ] = 0) $TelegramThreadId ] ] ];
|
||||||
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
|
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
|
||||||
|
|
||||||
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
|
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
|
||||||
|
@ -148,8 +189,8 @@
|
||||||
|
|
||||||
:local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
|
:local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
|
||||||
"&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \
|
"&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \
|
||||||
"&disable_web_page_preview=true&parse_mode=MarkdownV2");
|
"&disable_web_page_preview=true&parse_mode=MarkdownV2");
|
||||||
:do {
|
:onerror Err {
|
||||||
:if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
|
:if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
|
||||||
$LogPrint warning $0 ("Downloading required certificate failed.");
|
$LogPrint warning $0 ("Downloading required certificate failed.");
|
||||||
:error false;
|
:error false;
|
||||||
|
@ -158,8 +199,8 @@
|
||||||
("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \
|
("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \
|
||||||
http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
|
http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
|
||||||
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
|
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint info $0 ("Failed sending Telegram notification! Queuing...");
|
$LogPrint info $0 ("Failed sending Telegram notification: " . $Err . " - Queuing...");
|
||||||
|
|
||||||
:if ([ :typeof $TelegramQueue ] = "nothing") do={
|
:if ([ :typeof $TelegramQueue ] = "nothing") do={
|
||||||
:set TelegramQueue ({});
|
:set TelegramQueue ({});
|
||||||
|
@ -185,12 +226,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
# send notification via telegram - expects at least two string arguments
|
# send notification via telegram - expects at least two string arguments
|
||||||
:set SendTelegram do={ :do {
|
:set SendTelegram do={ :onerror Err {
|
||||||
:global SendTelegram2;
|
:global SendTelegram2;
|
||||||
|
|
||||||
$SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
$SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 });
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# send notification via telegram - expects one array argument
|
# send notification via telegram - expects one array argument
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
:global ScriptRunOnce;
|
:global ScriptRunOnce;
|
||||||
|
|
||||||
# fetch and run script(s) once
|
# fetch and run script(s) once
|
||||||
:set ScriptRunOnce do={ :do {
|
:set ScriptRunOnce do={ :onerror Err {
|
||||||
:local Scripts [ :toarray $1 ];
|
:local Scripts [ :toarray $1 ];
|
||||||
|
|
||||||
:global ScriptRunOnceBaseUrl;
|
:global ScriptRunOnceBaseUrl;
|
||||||
|
@ -41,16 +41,16 @@
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
$LogPrint info $0 ("Running script '" . $Script . "' now.");
|
$LogPrint info $0 ("Running script '" . $Script . "' now.");
|
||||||
[ :parse $Source ];
|
[ :parse $Source ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("The script '" . $Script . "' failed to run!");
|
$LogPrint warning $0 ("The script '" . $Script . "' failed to run: " . $Err);
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:return true;
|
:return true;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
:global SSHKeysImportFile;
|
:global SSHKeysImportFile;
|
||||||
|
|
||||||
# import single key passed as string
|
# import single key passed as string
|
||||||
:set SSHKeysImport do={ :do {
|
:set SSHKeysImport do={ :onerror Err {
|
||||||
:local Key [ :tostr $1 ];
|
:local Key [ :tostr $1 ];
|
||||||
:local User [ :tostr $2 ];
|
:local User [ :tostr $2 ];
|
||||||
|
|
||||||
|
@ -55,26 +55,27 @@
|
||||||
/file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5);
|
/file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5);
|
||||||
$WaitForFile $FileName;
|
$WaitForFile $FileName;
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
/user/ssh-keys/import public-key-file=$FileName user=$User;
|
/user/ssh-keys/import public-key-file=$FileName user=$User;
|
||||||
$LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \
|
$LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \
|
||||||
"MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'.");
|
"MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'.");
|
||||||
$RmDir "tmpfs/ssh-keys-import";
|
$RmDir "tmpfs/ssh-keys-import";
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $0 ("Failed importing key.");
|
$LogPrint warning $0 ("Failed importing key: " . $Err);
|
||||||
$RmDir "tmpfs/ssh-keys-import";
|
$RmDir "tmpfs/ssh-keys-import";
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
||||||
# import keys from a file
|
# import keys from a file
|
||||||
:set SSHKeysImportFile do={ :do {
|
:set SSHKeysImportFile do={ :onerror Err {
|
||||||
:local FileName [ :tostr $1 ];
|
:local FileName [ :tostr $1 ];
|
||||||
:local User [ :tostr $2 ];
|
:local User [ :tostr $2 ];
|
||||||
|
|
||||||
:global EitherOr;
|
:global EitherOr;
|
||||||
|
:global FileExists;
|
||||||
:global LogPrint;
|
:global LogPrint;
|
||||||
:global ParseKeyValueStore;
|
:global ParseKeyValueStore;
|
||||||
:global SSHKeysImport;
|
:global SSHKeysImport;
|
||||||
|
@ -84,8 +85,7 @@
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
:local File [ /file/find where name=$FileName ];
|
:if ([ $FileExists $FileName ] = true) do={
|
||||||
:if ([ :len $File ] = 0) do={
|
|
||||||
$LogPrint warning $0 ("File '" . $FileName . "' does not exist.");
|
$LogPrint warning $0 ("File '" . $FileName . "' does not exist.");
|
||||||
:return false;
|
:return false;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,7 @@
|
||||||
:foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={
|
:foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={
|
||||||
:local Continue false;
|
:local Continue false;
|
||||||
:if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={
|
:if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={
|
||||||
:do {
|
:if ([ $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User ] = false) do={
|
||||||
$SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User;
|
|
||||||
} on-error={
|
|
||||||
$LogPrint warning $0 ("Failed importing key for user '" . $User . "'.");
|
$LogPrint warning $0 ("Failed importing key for user '" . $User . "'.");
|
||||||
}
|
}
|
||||||
:set Continue true;
|
:set Continue true;
|
||||||
|
@ -109,6 +107,6 @@
|
||||||
$LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.");
|
$LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# act on multiple mode and reset button presses
|
# act on multiple mode and reset button presses
|
||||||
# https://rsc.eworm.de/doc/mode-button.md
|
# https://rsc.eworm.de/doc/mode-button.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global ModeButton;
|
:global ModeButton;
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
:if ([ :len $Scheduler ] = 0) do={
|
:if ([ :len $Scheduler ] = 0) do={
|
||||||
$LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses...");
|
$LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses...");
|
||||||
:global ModeButtonScheduler do={ :do {
|
:global ModeButtonScheduler do={ :onerror Err {
|
||||||
:local FuncName $0;
|
:local FuncName $0;
|
||||||
|
|
||||||
:global ModeButton;
|
:global ModeButton;
|
||||||
|
@ -69,11 +69,11 @@
|
||||||
:delay 200ms;
|
:delay 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
:do {
|
:onerror Err {
|
||||||
[ :parse $Code ];
|
[ :parse $Code ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $FuncName \
|
$LogPrint warning $FuncName \
|
||||||
("The code for " . $Count . " mode-button presses failed with runtime error!");
|
("The code for " . $Count . " mode-button presses failed with runtime error: " . $Err);
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
$LogPrint warning $FuncName \
|
$LogPrint warning $FuncName \
|
||||||
|
@ -82,8 +82,8 @@
|
||||||
} else={
|
} else={
|
||||||
$LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses.");
|
$LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses.");
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError false $0;
|
:global ExitError; $ExitError false $0 $Err;
|
||||||
} }
|
} }
|
||||||
/system/scheduler/add name="_ModeButtonScheduler" \
|
/system/scheduler/add name="_ModeButtonScheduler" \
|
||||||
on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s;
|
on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s;
|
||||||
|
@ -91,6 +91,6 @@
|
||||||
$LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler...");
|
$LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler...");
|
||||||
/system/scheduler/set $Scheduler start-time=[ /system/clock/get time ];
|
/system/scheduler/set $Scheduler start-time=[ /system/clock/get time ];
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
# monitor and manage dns/doh with netwatch
|
# monitor and manage dns/doh with netwatch
|
||||||
# https://rsc.eworm.de/doc/netwatch-dns.md
|
# https://rsc.eworm.de/doc/netwatch-dns.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global CertificateAvailable;
|
:global CertificateAvailable;
|
||||||
|
@ -118,15 +118,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:local Data false;
|
:local Data false;
|
||||||
:do {
|
:onerror Err {
|
||||||
:set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
:retry {
|
||||||
http-header-field=({ "accept: application/dns-message" }) \
|
:set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
|
||||||
url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \
|
http-header-field=({ "accept: application/dns-message" }) \
|
||||||
"\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \
|
url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \
|
||||||
"\00\10" . "\00\01") ]) as-value ]->"data");
|
"\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \
|
||||||
} on-error={
|
"\00\10" . "\00\01") ]) as-value ]->"data");
|
||||||
$LogPrint warning $ScriptName ("Request to DoH server failed (network or certificate issue): " . \
|
} delay=1s max=3;
|
||||||
($DohServer->"doh-url"));
|
} do={
|
||||||
|
$LogPrint warning $ScriptName ("Request to DoH server " . ($DohServer->"doh-url") . \
|
||||||
|
" failed: " . $Err);
|
||||||
}
|
}
|
||||||
|
|
||||||
:if ($Data != false) do={
|
:if ($Data != false) do={
|
||||||
|
@ -145,6 +147,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
# monitor netwatch and send notifications
|
# monitor netwatch and send notifications
|
||||||
# https://rsc.eworm.de/doc/netwatch-notify.md
|
# https://rsc.eworm.de/doc/netwatch-notify.md
|
||||||
|
|
||||||
:global GlobalFunctionsReady;
|
|
||||||
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
|
|
||||||
|
|
||||||
:local ExitOK false;
|
:local ExitOK false;
|
||||||
:do {
|
:onerror Err {
|
||||||
|
:global GlobalConfigReady; :global GlobalFunctionsReady;
|
||||||
|
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
|
||||||
|
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
|
||||||
:local ScriptName [ :jobname ];
|
:local ScriptName [ :jobname ];
|
||||||
|
|
||||||
:global NetwatchNotify;
|
:global NetwatchNotify;
|
||||||
|
@ -38,10 +38,10 @@
|
||||||
:global ValidateSyntax;
|
:global ValidateSyntax;
|
||||||
|
|
||||||
:if ([ $ValidateSyntax $Hook ] = true) do={
|
:if ([ $ValidateSyntax $Hook ] = true) do={
|
||||||
:do {
|
onerror Err {
|
||||||
[ :parse $Hook ];
|
[ :parse $Hook ];
|
||||||
} on-error={
|
} do={
|
||||||
$LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run.");
|
$LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run: " . $Err);
|
||||||
:return ("The hook failed to run.");
|
:return ("The hook failed to run.");
|
||||||
}
|
}
|
||||||
} else={
|
} else={
|
||||||
|
@ -61,15 +61,19 @@
|
||||||
:global GetRandom20CharAlNum;
|
:global GetRandom20CharAlNum;
|
||||||
|
|
||||||
:local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]);
|
:local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]);
|
||||||
/ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s;
|
:if ([ :typeof [ :toip $Expected ] ] = "ip") do={
|
||||||
:delay 20ms;
|
/ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s;
|
||||||
:if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
|
:delay 20ms;
|
||||||
:return true;
|
:if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
|
||||||
|
:return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s;
|
:if ([ :typeof [ :toip6 $Expected ] ] = "ip6") do={
|
||||||
:delay 20ms;
|
/ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s;
|
||||||
:if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
|
:delay 20ms;
|
||||||
:return true;
|
:if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
|
||||||
|
:return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:return false;
|
:return false;
|
||||||
|
@ -103,7 +107,7 @@
|
||||||
|
|
||||||
:if ([ :typeof ($HostInfo->"resolve") ] = "str") do={
|
:if ([ :typeof ($HostInfo->"resolve") ] = "str") do={
|
||||||
:if ([ $IsDNSResolving ] = true) do={
|
:if ([ $IsDNSResolving ] = true) do={
|
||||||
:do {
|
:onerror Err {
|
||||||
:local Resolve [ :resolve type=[ $IfThenElse ([ :typeof ($HostVal->"host") ] = "ip") \
|
:local Resolve [ :resolve type=[ $IfThenElse ([ :typeof ($HostVal->"host") ] = "ip") \
|
||||||
"ipv4" "ipv6" ] ($HostInfo->"resolve") ];
|
"ipv4" "ipv6" ] ($HostInfo->"resolve") ];
|
||||||
:if ($Resolve != $HostVal->"host") do={
|
:if ($Resolve != $HostVal->"host") do={
|
||||||
|
@ -117,13 +121,13 @@
|
||||||
:set ($HostVal->"status") "unknown";
|
:set ($HostVal->"status") "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1);
|
:set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1);
|
||||||
:if ($Metric->"resolve-failcnt" = 3) do={
|
:if ($Metric->"resolve-failcnt" = 3) do={
|
||||||
$LogPrint [ $IfThenElse ($HostInfo->"no-resolve-fail" != true) warning debug ] \
|
$LogPrint [ $IfThenElse ($HostInfo->"no-resolve-fail" != true) warning debug ] \
|
||||||
$ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \
|
$ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \
|
||||||
($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \
|
($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \
|
||||||
$HostInfo->"name") "" ] . "' failed.");
|
$HostInfo->"name") "" ] . "' failed: " . $Err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +224,6 @@
|
||||||
"since"=($Metric->"since") };
|
"since"=($Metric->"since") };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
} do={
|
||||||
:global ExitError; $ExitError $ExitOK [ :jobname ];
|
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically.";
|
132="Split off plugins from 'check-health', so the script works on all devices to monitor CPU and RAM. The supported plugins for sensors in hardware are installed automatically.";
|
||||||
133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added.";
|
133="Updated the default configuration for 'fw-addr-lists', deprecated lists were removed, a collective list was added.";
|
||||||
134="Enhanced 'mod/notification-telegram' and 'telegram-chat' to support topics in groups.";
|
134="Enhanced 'mod/notification-telegram' and 'telegram-chat' to support topics in groups.";
|
||||||
|
135="Introduced helper function '\$GetTelegramChatId' for 'mod/notification-telegram' which helps retrieve information.";
|
||||||
|
136="Introduced script 'check-perpetual-license' to check for license state on CHR.";
|
||||||
|
137="Added support to send notifications via Gotify (gotify.net).";
|
||||||
|
138="RouterOS 7.19 is suffering an issue with certificate store. Fixing trust state for all certificates...";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Migration steps to be applied on script updates
|
# Migration steps to be applied on script updates
|
||||||
|
@ -68,4 +72,5 @@
|
||||||
104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;";
|
104=":global CharacterReplace; :global ScriptInstallUpdate; :foreach Script in={ \"capsman-download-packages\"; \"capsman-rolling-upgrade\"; \"hotspot-to-wpa\"; \"hotspot-to-wpa-cleanup\" } do={ /system/script/set name=(\$Script . \".capsman\") [ find where name=\$Script ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~(\$Script . \"([^-.]|\\\$)\") ] do={ /system/scheduler/set \$Scheduler on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Script (\$Script . \".capsman\") ]; }; }; /ip/hotspot/user/profile/set on-login=\"hotspot-to-wpa.capsman\" [ find where on-login=\"hotspot-to-wpa\" ]; \$ScriptInstallUpdate;";
|
||||||
111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }";
|
111=":local Rec [ /ip/dns/static/find where comment~\"^managed by dhcp-to-dns for \" ]; :if ([ :len \$Rec ] > 0) do={ /ip/dns/static/remove \$Rec; /system/script/run dhcp-to-dns; }";
|
||||||
132=":if ([ :len [ /system/script/find where name=\"check-health\" ] ] > 0) do={ :local Code \":local Install \\\"check-health\\\"; :if ([ :len [ /system/health/find where type=\\\"\\\" name~\\\"-state\\\\\\\$\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/state\\\"); }; :if ([ :len [ /system/health/find where type=\\\"C\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/temperature\\\"); }; :if ([ :len [ /system/health/find where type=\\\"V\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/voltage\\\"); }; :global ScriptInstallUpdate; \\\$ScriptInstallUpdate \\\$Install;\"; :global ValidateSyntax; :if ([ \$ValidateSyntax \$Code ] = true) do={ :do { [ :parse \$Code ]; } on-error={ }; }; }";
|
132=":if ([ :len [ /system/script/find where name=\"check-health\" ] ] > 0) do={ :local Code \":local Install \\\"check-health\\\"; :if ([ :len [ /system/health/find where type=\\\"\\\" name~\\\"-state\\\\\\\$\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/state\\\"); }; :if ([ :len [ /system/health/find where type=\\\"C\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/temperature\\\"); }; :if ([ :len [ /system/health/find where type=\\\"V\\\" ] ] > 0) do={ :set Install (\\\$Install . \\\",check-health.d/voltage\\\"); }; :global ScriptInstallUpdate; \\\$ScriptInstallUpdate \\\$Install;\"; :global ValidateSyntax; :if ([ \$ValidateSyntax \$Code ] = true) do={ :do { [ :parse \$Code ]; } on-error={ }; }; }";
|
||||||
|
138="/certificate/set trusted=yes [ find where trusted=yes ];";
|
||||||
};
|
};
|
||||||
|
|