Compare commits

...

65 commits

Author SHA1 Message Date
Christian Hesse
ce39b79f69 capsman-download-packages: fix parameter for $RmFile
The function can not handle ids, we have to pass a name instead.
2025-03-13 11:50:38 +01:00
Christian Hesse
20bf609c44 check-routeros-update: fix condition for license check
Turns out that `next-renewal-at` is moved forward when renewal failed,
so it never matches the criteria. Just start complaining three weeks
before deadline.
2025-03-13 10:51:39 +01:00
Christian Hesse
b63e0fcb2f netwatch-notify: check matching address type only 2025-03-12 11:26:22 +01:00
Christian Hesse
1555426687 netwatch-notify: increase the timeout even more
This interacts with the number of addresses in the address-list. Having
a lot of addresses there (for exemple from script 'fw-addr-lists' 😜)
makes the 'find' take longer. We have to make sure that 'find' succeeds
before the address times out.

As this does not hurt... Let's just bump to 10 seconds to be safe.
2025-03-12 11:18:18 +01:00
Christian Hesse
97b99316b2 netwatch-notify: increase timeout...
... as a timeout of one second expires immediately. 🤨
2025-03-12 10:31:11 +01:00
Christian Hesse
788400c458 fw-addr-lists: raw.githubusercontent.com requires 'USERTrust RSA Certification Authority' now 2025-03-11 15:51:25 +01:00
Christian Hesse
eb59dd21ca check-routeros-update: check perpetual license...
... as these have to be renewed and can expire.
2025-03-11 15:51:25 +01:00
Christian Hesse
79a4b369cb Merge branch 'fw-addr-lists' into next 2025-03-11 15:51:25 +01:00
Christian Hesse
f0e6cbcfe1 fw-addr-lists: get branch from calculated checksum
The addresses were spread very uneven before.

Let's calculate a checksum, and take the first two characters of that.
The addresses are now spread evenly on 256 branches (0x00 to 0xff).
2025-03-11 15:51:10 +01:00
Christian Hesse
d71ea804b0 fw-addr-lists: two characters for branch
Using one character for IPv4 is ok (1 to 9), but IPv6 global unicase
(2000::/3) results in just two different characters (2 and 3).

So let's use first two characters...
2025-03-11 14:20:50 +01:00
Christian Hesse
e148df9e57 fw-addr-lists: put addresses into "branches"...
... effectively adding another layer and some complexity, but:
The addresses are sorted inside the array, and sorting less addresses in
a branch saves a lot of processing power. So this is a lot faster now...
2025-03-11 14:20:44 +01:00
Christian Hesse
2f55bfaf00 fw-addr-lists: strip cidr for host addresses
This makes sure the addresses match later when we read them from
address-list for renew.
2025-03-11 14:19:10 +01:00
Christian Hesse
ea6de35699 fw-addr-lists: do not clean up
Cleanup is important on renew (so the script does not attempt to re-add),
but we do not care here.
2025-03-11 14:13:55 +01:00
Christian Hesse
fb343c99e3 fw-addr-lists: put timeout into variable 2025-03-06 22:59:31 +01:00
Christian Hesse
7be26a0712 DEBUG: add info on $LogPrintVerbose 2025-03-06 15:59:44 +01:00
Christian Hesse
6d718ec987 fw-addr-lists: use $LogPrintVerbose ...
... to reduce debug output and speed up execution.
2025-03-06 15:59:44 +01:00
Christian Hesse
e341e1c30c global-functions: introduce $LogPrintVerbose ...
... which is a declared function, but has no code, intentionally. It can be
called as a no-op by default.

If you want this output set the function to be the same as $LogPrint:

    :set LogPrintVerbose $LogPrint;
2025-03-06 15:59:11 +01:00
Christian Hesse
b43b1b3955 Merge branch 'checksums' into next 2025-03-06 10:43:15 +01:00
Christian Hesse
1b46a5fd9b global-functions: $ScriptInstallUpdate: checksum only for same source
So ignore if script is fetched from different base or with different
suffix.
2025-03-06 10:43:13 +01:00
Christian Hesse
b13360e4b8 global-functions: $ScriptInstallUpdate: simplify check
This one should suffice...
2025-03-06 10:42:52 +01:00
Christian Hesse
c9de6d8579 global-functions: $ScriptInstallUpdate: put checksum into variable 2025-03-06 10:42:27 +01:00
Christian Hesse
10374afc18 global-functions: $ScriptInstallUpdate: support checksums for CRLF scripts 2025-03-06 10:42:00 +01:00
Christian Hesse
0c1d96f89d global-functions: $ScriptInstallUpdate: get and compare checksums
The file 'checksums.json' is generated when deploying to my web
server... This should speed up the update a lot as it reduces downloads
to a minimum. 🎉😁
2025-03-06 10:41:28 +01:00
Christian Hesse
3ccaafd1b3 global-functions: $ScriptInstallUpdate: move code into block 2025-03-05 01:15:22 +01:00
Christian Hesse
469f783a92 ipv6-update: check for availability of both variables 2025-03-03 09:12:43 +01:00
Christian Hesse
33c02e0609 ipv6-update: ignore if prefix is no longer valid 2025-03-03 09:10:54 +01:00
Christian Hesse
6331505dbe Merge branch 'quote-file-name' into next
This is required with RouterOS 7.18 now...

Well, probably the change was introduced with one of the
beta versions...
2025-02-27 10:52:52 +01:00
Christian Hesse
0c4fb42616 mod/notification-telegram: $GetTelegramChatId: give thead id...
... if message was sent to group's topic.
2025-02-27 10:52:52 +01:00
Christian Hesse
f5189b8bd7 INITIAL-COMMANDS: quote the certificate file name 2025-02-27 10:52:52 +01:00
Christian Hesse
e2fe653035 mod/notification-telegram: $GetTelegramChatId: use last message 2025-02-27 10:52:52 +01:00
Christian Hesse
b11be59b08 README: quote the certificate file name 2025-02-27 10:52:52 +01:00
Christian Hesse
24de060904 Merge branch 'check-certificates' into next 2025-02-27 10:52:19 +01:00
Christian Hesse
14195c51ca check-certificates: try PKCS#12 before PEM...
... as that is more likely to have a private key.

Is that true? 🤨
2025-02-26 18:25:58 +01:00
Christian Hesse
e833dfcf25 check-certificates: simplify return from function...
... and also break earch on success.
2025-02-26 18:05:32 +01:00
Christian Hesse
512c54bd59 check-certificates: ... and even more 2025-02-26 18:05:32 +01:00
Christian Hesse
3d40b4419d check-certificates: add more debug output 2025-02-26 18:03:45 +01:00
Christian Hesse
a6d4e7e82c check-certificates: drop dot from type...
... and add it in file name.
2025-02-26 18:03:17 +01:00
Christian Hesse
f6c2225f68 check-certificates: catch and ignore import error
Hmm... 🤨 When was that runtime error introduced? I *think* it
worked before.
2025-02-26 13:57:51 +01:00
Christian Hesse
53b13b295a mod/notification-telegram: introduce $GetTelegramChatId 2025-02-25 22:37:30 +01:00
Christian Hesse
4eafcaa3ac telegram-chat: say hello when awaiting commands 2025-02-25 22:16:48 +01:00
Christian Hesse
c33eb41c9c global-functions: $DeviceInfo: add license level, re-order 2025-02-25 17:55:26 +01:00
Christian Hesse
78f9687558 Merge branch 'telegram-topics' into next 2025-02-25 17:55:26 +01:00
Christian Hesse
e5de9de391 notify on support for Telegram group topics 2025-02-25 17:55:26 +01:00
Christian Hesse
7928c5f054 telegram-chat: support reply in group's topic 2025-02-25 17:55:26 +01:00
Christian Hesse
757fa60e6f telegram-chat: make $IsReply a boolean...
... and check for correct data type.

We need this for a group with topic feature enabled, as that variable is
set there, but is is an array.
2025-02-25 17:55:26 +01:00
Christian Hesse
a22b62f588 mod/notification-telegram: support sending to group's topic...
... when a group has enabled the "Topics" feature.
2025-02-25 17:55:12 +01:00
Christian Hesse
cad104879c mod/notification-telegram: simplify the queue...
... and pass http-data as a complete sting.
2025-02-24 15:18:53 +01:00
Christian Hesse
58da92e36a global-functions: $WaitForFile: drop the warning on file handling breakage...
... but keep the workaround for now - just to be sure.
2025-02-19 22:21:03 +01:00
Christian Hesse
2c92c78b46 global-functions: $ScriptInstallUpdate: also show commit info 2025-02-17 13:55:44 +01:00
Christian Hesse
75633872aa global-functions: $DeviceInfo: also show commit info 2025-02-17 13:55:36 +01:00
Christian Hesse
dafcc1a0cb global-functions: $RmFile: fix type safeguard
Ups... 🫣
The type is not just literal 'file' - but what ever type the file is,
like 'backup', 'package', 'script', '.conf file', ...

So let's match those types we do *not* want to remove.

Fixes: https://github.com/eworm-de/routeros-scripts/issues/90
2025-02-13 17:58:48 +01:00
Christian Hesse
0199ea8884 global-functions: $ScriptInstallUpdate: show commit id (if available) 2025-02-13 09:50:22 +01:00
Christian Hesse
584e507fd1 global-functions: $DeviceInfo: show commit id (if available) 2025-02-13 09:03:05 +01:00
Christian Hesse
5715bc7b57 mod/scriptrunonce: always give proper return code 2025-02-12 17:40:27 +01:00
Christian Hesse
1c957dbc6d mod/scriptrunonce: resolve nested conditions 2025-02-12 17:40:27 +01:00
Christian Hesse
b7b3b43f3b mod/scriptrunonce: use $FetchHuge 2025-02-12 17:40:27 +01:00
Christian Hesse
df631b987d fw-addr-lists: add a collective list in default configuration 2025-02-12 17:40:27 +01:00
Christian Hesse
c8759381e9 global-functions: $WaitForFile: check that we can get properties
Looks like RouterOS 7.18beta2 brings more breakage. Having a file
available in listing is just the first step now. We also need to make
sure that the file properties are accessible... 🤪

I have seen this taking several tens of seconds at least... 🤪🤪 So
let's just try until we have properties available, or the file vanishes.

Reported as SUP-179200. 🤞
2025-02-12 10:49:38 +01:00
Christian Hesse
d41f758550 introduce DEBUG info 2025-02-12 10:49:34 +01:00
Christian Hesse
e1c561dd91 global-functions: $MkDir: add debug output 2025-02-11 14:56:43 +01:00
Christian Hesse
4d0b4a1ff4 fw-addr-lists: these lists are deprecated and discontinued
Any alternatives around?
2025-02-11 14:30:14 +01:00
Christian Hesse
8af67af462 doc/log-forward: mention ntfy 2025-02-10 15:31:20 +01:00
Christian Hesse
da280586b5 doc/log-forward: add a hint on defaults 2025-02-10 15:31:20 +01:00
Christian Hesse
2e42f7963c mod/notification-ntfy: use empty strings as default...
... which should be fine now that the credentials are not passed with
fetch's properties, but as properly formatted authentication header.
2025-02-10 15:23:50 +01:00
Christian Hesse
fc3beac83b log-forward: make empty string a special meaning 2025-02-10 15:23:50 +01:00
25 changed files with 429 additions and 166 deletions

63
DEBUG.md Normal file
View file

@ -0,0 +1,63 @@
Debug output and logs
=====================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/)
[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts)
[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)
[⬅️ Go back to main README](README.md)
Sometimes scripts do not behave as expected. In these cases debug output
or logs can help.
## Debug output
Run this command in a terminal:
:set PrintDebug true;
You will then see debug output when running the script from terminal.
To revert to default output run:
:set PrintDebug false;
### Debug output for specific script
Even having debug output for a specific script or function only (or a
set of) is possible. To enable debug output for `telegram-chat` run:
:set ($PrintDebugOverride->"telegram-chat") true;
## Debug logs
The debug info can go to system log. To make it show up in `memory` run:
/system/logging/add topics=script,debug action=memory;
Other actions (`disk`, `email`, `remote` or `support`) can be used as
well. I do not recommend using `echo` - use [debug output](#debug-output)
instead.
Disable or remote 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 top](#top)

View file

@ -19,7 +19,7 @@ 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;
:delay 1s;
/certificate/import file-name=isrg-root-x2.pem passphrase="";
/certificate/import file-name="isrg-root-x2.pem" passphrase="";
:if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={
:error "Something is wrong with your certificates!";
};

View file

@ -87,7 +87,7 @@ file to your MikroTik device.
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
a sensitive property, the passphrase.

View file

@ -62,7 +62,7 @@
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
($File->"package-architecture") $PackagePath ] = true) do={
:set Updated true;
$RmFile $Package;
$RmFile ($File->"name");
}
}

View file

@ -64,7 +64,7 @@
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
($File->"package-architecture") $PackagePath ] = true) do={
:set Updated true;
$RmFile $Package;
$RmFile ($File->"name");
}
}

View file

@ -62,7 +62,7 @@
:if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \
($File->"package-architecture") $PackagePath ] = true) do={
:set Updated true;
$RmFile $Package;
$RmFile ($File->"name");
}
}

View file

@ -1,28 +0,0 @@
# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
# Label: "GlobalSign Root CA - R3"
# Serial: 4835703278459759426209954
# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----

View file

@ -15,7 +15,7 @@ DOMAINS_DUAL = \
git.eworm.de/ISRG-Root-X2 \
lists.blocklist.de/Certum-Trusted-Network-CA \
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 \
upgrade.mikrotik.com/ISRG-Root-X1
DOMAINS_IPV4 = \
@ -23,12 +23,10 @@ DOMAINS_IPV4 = \
8.8.8.8/GTS-Root-R1 \
9.9.9.9/DigiCert-Global-Root-G3 \
api.mullvad.net/ISRG-Root-X1 \
feodotracker.abuse.ch/GlobalSign \
ipv4.showipv6.de/ISRG-Root-X1 \
ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \
mkcert.org/ISRG-Root-X1 \
ntfy.sh/ISRG-Root-X1 \
sslbl.abuse.ch/GlobalSign \
www.dshield.org/ISRG-Root-X1 \
www.spamhaus.org/GTS-Root-R4
DOMAINS_IPV6 = \

View 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-----

View file

@ -48,21 +48,26 @@
:global UrlEncode;
: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 {
/tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
$WaitForFile $CertFileName;
:local DecryptionFailed true;
:foreach PassPhrase in=$CertRenewPass do={
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
:if ($Result->"decryption-failures" = 0) do={
:set DecryptionFailed false;
}
:foreach I,PassPhrase in=$CertRenewPass do={
:do {
$LogPrint debug $ScriptName ("Trying " . $I . ". passphrase... ");
: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;
@ -77,13 +82,13 @@
$CertificateNameByCN [ /certificate/get $CertInChain common-name ];
}
:set Return true;
:return true;
} on-error={
$LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'.");
}
}
:return $Return;
:return false;
}
:local FormatInfo do={

View file

@ -66,6 +66,27 @@
:error "A reboot for update is already scheduled.";
}
:local License [ /system/license/get ];
:if ([ :typeof ($License->"deadline-at") ] = "str") do={
:if ([ :len ($License->"next-renewal-at") ] = 0 && ($License->"limited-upgrades") = true) do={
$LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!");
$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 ExitOK true;
:error false;
}
:if ([ :totime ($License->"deadline-at") ] - 3w < [ :timestamp ]) do={
$LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!");
$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 . "...") });
}
}
$LogPrint debug $ScriptName ("Checking for updates...");
/system/package/update/check-for-updates without-paging as-value;
:local Update [ /system/package/update/get ];

View file

@ -18,10 +18,11 @@ Description
This script downloads, imports and updates firewall address-lists. Its main
purpose is to block attacking ip addresses, spam hosts, command-and-control
servers and similar malicious entities. The default configuration contains
lists from [abuse.ch](https://abuse.ch/), [dshield.org](https://dshield.org/)
and [blocklist.de](https://www.blocklist.de/), and
lists from [spamhaus.org](https://spamhaus.org/) are prepared.
servers and similar malicious entities. The default configuration contains a
[collective list by GitHub user @stamparm](https://github.com/stamparm/ipsum),
lists from [dshield.org](https://dshield.org/) and
[blocklist.de](https://www.blocklist.de/), and lists from
[spamhaus.org](https://spamhaus.org/) are prepared.
The address-lists are updated in place, so after initial import you will not
see situation when the lists are not populated.

View file

@ -22,15 +22,15 @@ server (see `/system/logging`). This has some limitation, however:
* does not work early after boot if network connectivity is not
yet established, or breaks intermittently
* lots of messages generate a flood of mails
* Matrix and Telegram are not supported
* Matrix, Ntfy and Telegram are not supported
The script works around the limitations, for example it does:
* read from `/log`, including messages from early boot
* skip multi-repeated messages
* rate-limit itself to mitigate flooding
* forward via notification (which includes *e-mail*, *Matrix* and *Telegram*
when installed and configured, see below)
* forward via notification (which includes *e-mail*, *Matrix*, *Ntfy* and
*Telegram* when installed and configured, see below)
It is intended to be run periodically from scheduler, then collects new
log messages and forwards them via notification.
@ -53,6 +53,12 @@ Just install the script:
Configuration
-------------
The default configuration should provide reasonable presets, filtering
*info*, and effectively forwarding *warning* and *error*.
> 💡️ **Hint**: Please try with defaults first, especially if you are not
> familiar with regular expressions!
The configuration goes to `global-config-overlay`, these are the parameters:
* `LogForwardFilter`: define topics *not* to be forwarded

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -38,14 +38,21 @@ create your own bot:
![create new bot](notification-telegram.d/newbot.avif)
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
with the `START` button. It will send you some information, including the
`id`, just below `You`.
:set TelegramTokenId "5214364459:AAHLwf1o7ybbKDo6pY24Kd2bZ5rjCakDXTc";
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;
![get chat id](notification-telegram.d/getchatid.avif)
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.
> **Info**: Copy relevant configuration from
@ -54,9 +61,13 @@ reload the configuration.
### Notifications to a group
Sending notifications to a group is possible as well. Add your bot and the
*GetIDs Bot* to a group, then use the group's id (which starts with a dash)
for `TelegramChatId`. Then remove *GetIDs Bot* from group.
Sending notifications to a group is possible as well. Add your bot to a group
and make it an admin (required for read access!) and send a message and run
`$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
specific topic in a group.
Usage and invocation
--------------------

View file

@ -24,6 +24,7 @@
:global HumanReadableNum;
:global LogPrint;
:global LogPrintOnce;
:global LogPrintVerbose;
:global ScriptLock;
:global WaitFullyConnected;
@ -36,6 +37,11 @@
}
}
: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={
:set ExitOK true;
:error false;
@ -99,17 +105,24 @@
:set Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr"));
}
: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={
:set ($IPv4Addresses->$Address) $TimeOut;
:if ($Address ~ "/32\$") do={
:set Address [ :pick $Address 0 ([ :len $Address ] - 3) ];
}
:set ($IPv4Addresses->$Branch->$Address) $TimeOut;
:error true;
}
:if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$") do={
:set ($IPv6Addresses->$Address) $TimeOut;
:if ($Address ~ "/128\$") do={
:set Address [ :pick $Address 0 ([ :len $Address ] - 4) ];
}
:set ($IPv6Addresses->$Branch->$Address) $TimeOut;
:error true;
}
:if ($Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={
:set ($IPv4Addresses->$Address) $TimeOut;
:set ($IPv6Addresses->$Address) $TimeOut;
:set ($IPv4Addresses->$Branch->$Address) $TimeOut;
:set ($IPv6Addresses->$Branch->$Address) $TimeOut;
:error true;
}
} on-error={ }
@ -119,15 +132,17 @@
:foreach Entry in=[ /ip/firewall/address-list/find where \
list=$FwListName comment=$ListComment ] do={
:local Address [ /ip/firewall/address-list/get $Entry address ];
:if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={
$LogPrint debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \
"' with " . ($IPv4Addresses->$Address) . ": " . $Address);
/ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address);
:set ($IPv4Addresses->$Address);
:local Branch [ $GetBranch $Address ];
:local TimeOut ($IPv4Addresses->$Branch->$Address);
:if ([ :typeof $TimeOut ] = "time") do={
$LogPrintVerbose debug $ScriptName ("Renewing IPv4 address in list '" . $FwListName . \
"' with " . $TimeOut . ": " . $Address);
/ip/firewall/address-list/set $Entry timeout=$TimeOut;
:set ($IPv4Addresses->$Branch->$Address);
:set CntRenew ($CntRenew + 1);
} else={
:if ($Failure = false) do={
$LogPrint debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \
$LogPrintVerbose debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \
"': " . $Address);
/ip/firewall/address-list/remove $Entry;
:set CntRemove ($CntRemove + 1);
@ -138,15 +153,17 @@
:foreach Entry in=[ /ipv6/firewall/address-list/find where \
list=$FwListName comment=$ListComment ] do={
:local Address [ /ipv6/firewall/address-list/get $Entry address ];
:if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={
$LogPrint debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \
"' with " . ($IPv6Addresses->$Address) . ": " . $Address);
/ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address);
:set ($IPv6Addresses->$Address);
:local Branch [ $GetBranch $Address ];
:local TimeOut ($IPv6Addresses->$Branch->$Address);
:if ([ :typeof $TimeOut ] = "time") do={
$LogPrintVerbose debug $ScriptName ("Renewing IPv6 address in list '" . $FwListName . \
"' with " . $TimeOut . ": " . $Address);
/ipv6/firewall/address-list/set $Entry timeout=$TimeOut;
:set ($IPv6Addresses->$Branch->$Address);
:set CntRenew ($CntRenew + 1);
} else={
:if ($Failure = false) do={
$LogPrint debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \
$LogPrintVerbose debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \
"': " . $Address);
/ipv6/firewall/address-list/remove $Entry;
:set CntRemove ($CntRemove + 1);
@ -154,31 +171,35 @@
}
}
:foreach Address,Timeout in=$IPv4Addresses do={
$LogPrint debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \
"' with " . $Timeout . ": " . $Address);
:do {
/ip/firewall/address-list/add list=$FwListName comment=$ListComment \
address=$Address timeout=$Timeout;
:set ($IPv4Addresses->$Address);
:set CntAdd ($CntAdd + 1);
} on-error={
$LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \
"': " . $Address);
:foreach BranchName,Branch in=$IPv4Addresses do={
$LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName);
:foreach Address,Timeout in=$Branch do={
$LogPrintVerbose debug $ScriptName ("Adding IPv4 address to list '" . $FwListName . \
"' with " . $Timeout . ": " . $Address);
:do {
/ip/firewall/address-list/add list=$FwListName comment=$ListComment \
address=$Address timeout=$Timeout;
:set CntAdd ($CntAdd + 1);
} on-error={
$LogPrint warning $ScriptName ("Failed to add IPv4 address to list '" . $FwListName . \
"': " . $Address);
}
}
}
:foreach Address,Timeout in=$IPv6Addresses do={
$LogPrint debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \
"' with " . $Timeout . ": " . $Address);
:do {
/ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \
address=$Address timeout=$Timeout;
:set ($IPv6Addresses->$Address);
:set CntAdd ($CntAdd + 1);
} on-error={
$LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \
"': " . $Address);
:foreach BranchName,Branch in=$IPv6Addresses do={
$LogPrintVerbose debug $ScriptName ("Handling branch: " . $BranchName);
:foreach Address,Timeout in=$Branch do={
$LogPrintVerbose debug $ScriptName ("Adding IPv6 address to list '" . $FwListName . \
"' with " . $Timeout . ": " . $Address);
:do {
/ipv6/firewall/address-list/add list=$FwListName comment=$ListComment \
address=$Address timeout=$Timeout;
:set CntAdd ($CntAdd + 1);
} on-error={
$LogPrint warning $ScriptName ("Failed to add IPv6 address to list '" . $FwListName . \
"': " . $Address);
}
}
}

View file

@ -33,6 +33,8 @@
:global TelegramChatId "";
#:global TelegramTokenId "123456:ABCDEF-GHI";
#:global TelegramChatId "12345678";
# Use this to send notifications to a specific topic in group.
:global TelegramThreadId "";
# Using telegram-chat you have to define trusted chat ids (not group ids!)
# or user names. Groups allow to chat with devices simultaneously.
#:global TelegramChatIdsTrusted {
@ -56,9 +58,9 @@
# install the module:
# $ScriptInstallUpdate mod/notification-ntfy
:global NtfyServer "ntfy.sh";
:global NtfyServerUser [];
:global NtfyServerPass [];
:global NtfyServerToken [];
:global NtfyServerUser "";
:global NtfyServerPass "";
:global NtfyServerToken "";
:global NtfyTopic "";
# It is possible to override e-mail, Telegram, Matrix and Ntfy setting
@ -90,6 +92,7 @@
:global BackupPartitionCopyBeforeFeatureUpdate false;
# This defines the settings for firewall address-lists (fw-addr-lists).
# Warning: Mind your device's resources - memory and processing!
:global FwAddrLists {
# "allow"={
# { url="https://rsc.eworm.de/main/fw-addr-lists.d/allow";
@ -98,10 +101,9 @@
"block"={
# { url="https://rsc.eworm.de/main/fw-addr-lists.d/block";
# cert="ISRG Root X2" };
{ url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt";
cert="GlobalSign" };
{ url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt";
cert="GlobalSign" };
{ 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
cert="USERTrust RSA Certification Authority" };
{ url="https://www.dshield.org/block.txt"; cidr="/24";
cert="ISRG Root X1" };
{ url="https://lists.blocklist.de/lists/strongips.txt";
@ -119,17 +121,17 @@
:global FwAddrListTimeOut 1d;
# This defines what log messages to filter or include by topic or message
# text. Regular expressions are supported. Do *NOT* set an empty string,
# that will filter or include everything!
# text. Regular expressions are supported. An empty string has a special
# meaning not to filter or include anything.
# These are filters, so excluding messages from forwarding.
:global LogForwardFilter "(debug|info|packet|raw)";
:global LogForwardFilterMessage [];
:global LogForwardFilterMessage "";
#:global LogForwardFilterMessage "message text";
#:global LogForwardFilterMessage "(message text|another text|...)";
# ... and another setting with reverse logic. This includes messages even
# if filtered above.
:global LogForwardInclude [];
:global LogForwardIncludeMessage [];
:global LogForwardInclude "";
:global LogForwardIncludeMessage "";
#:global LogForwardInclude "account";
#:global LogForwardIncludeMessage "message text";

View file

@ -12,8 +12,10 @@
:local ScriptName [ :jobname ];
# expected configuration version
:global ExpectedConfigVersion 132;
# Git commit id & info, expected configuration version
:global CommitId "unknown";
:global CommitInfo "unknown";
:global ExpectedConfigVersion 135;
# global variables not to be changed by user
:global GlobalFunctionsReady false;
@ -53,6 +55,7 @@
:global IsTimeSync;
:global LogPrint;
:global LogPrintOnce;
:global LogPrintVerbose;
:global MAX;
:global MIN;
:global MkDir;
@ -284,6 +287,8 @@
# get readable device info
:set DeviceInfo do={
:global CommitId;
:global CommitInfo;
:global ExpectedConfigVersion;
:global Identity;
@ -305,16 +310,19 @@
([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \
[ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \
([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \
[ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \
[ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \
"Hardware:\n" . \
[ $FormatLine " Board" ($Resource->"board-name") ] . "\n" . \
[ $FormatLine " Arch" ($Resource->"architecture-name") ] . "\n" . \
[ $IfThenElse ($RouterBoard->"routerboard" = true) \
([ $FormatLine "Model" ($RouterBoard->"model") ] . \
([ $FormatLine " Model" ($RouterBoard->"model") ] . \
[ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \
(" " . $RouterBoard->"revision") ] . "\n" . \
[ $FormatLine "Serial number" ($RouterBoard->"serial-number") ] . "\n") ] . \
[ $IfThenElse ([ :len ($License->"level") ] > 0) \
([ $FormatLine "License" ($License->"level") ] . "\n") ] . \
[ $FormatLine " Serial" ($RouterBoard->"serial-number") ] . "\n") ] . \
[ $IfThenElse ([ :len ($License->"nlevel") ] > 0) \
([ $FormatLine " License" ("level " . ($License->"nlevel")) ] . "\n") ] . \
"RouterOS:\n" . \
[ $IfThenElse ([ :len ($License->"level") ] > 0) \
([ $FormatLine " License" ("level " . ($License->"level")) ] . "\n") ] . \
[ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \
[ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \
[ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \
@ -324,6 +332,8 @@
$RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \
([ $FormatLine " Firmware" ($RouterBoard->"current-firmware") ] . "\n") ] . \
"RouterOS-Scripts:\n" . \
[ $IfThenElse ($CommitId != "unknown") \
([ $FormatLine " Commit" ($CommitInfo . "/" . [ :pick $CommitId 0 8 ]) ] . "\n") ] . \
[ $FormatLine " Version" $ExpectedConfigVersion ]);
}
@ -839,6 +849,9 @@
:return true;
}
# The function $LogPrintVerbose is declared, but has no code, intentionally.
# https://rsc.eworm.de/DEBUG.md#verbose-output
# get max value
:set MAX do={
:if ($1 > $2) do={ :return $1; }
@ -891,7 +904,10 @@
:return true;
}
$LogPrint debug $0 ("Making directory: " . $Path);
:if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={
$LogPrint debug $0 ("... which already exists.");
:return true;
}
@ -1047,12 +1063,12 @@
$LogPrint debug $0 ("Removing file: ". $FileName);
:if ([ :len [ /file/find where name=$FileName type!=file ] ] > 0) do={
:if ([ :len [ /file/find where name=$FileName (type=directory or type=disk) ] ] > 0) do={
$LogPrint error $0 ("File '" . $FileName . "' is not a file.");
:return false;
}
:local File [ /file/find where name=$FileName type=file ];
:local File [ /file/find where name=$FileName !(type=directory or type=disk) ];
:if ([ :len $File ] = 0) do={
$LogPrint debug $0 ("... which does not exist.");
:return true;
@ -1098,6 +1114,8 @@
:local Scripts [ :toarray $1 ];
:local NewComment [ :tostr $2 ];
:global CommitId;
:global CommitInfo;
:global ExpectedConfigVersion;
:global Identity;
:global IDonate;
@ -1130,11 +1148,20 @@
}
}
:local CommitIdBefore $CommitId;
:local ExpectedConfigVersionBefore $ExpectedConfigVersion;
:local ReloadGlobalFunctions false;
:local ReloadGlobalConfig false;
: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={
:local ScriptVal [ /system/script/get $Script ];
:local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ];
@ -1148,7 +1175,19 @@
}
}
:if (!($ScriptInfo->"ignore" = true)) 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;
}
:do {
:local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ];
:local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ];
@ -1167,10 +1206,9 @@
} else={
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!");
}
:error false;
}
}
:do {
:if ([ :len $SourceNew ] = 0) do={
$LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'.");
:error false;
@ -1244,6 +1282,10 @@
}
}
:if ($CommitId != "unknown" && $CommitIdBefore != $CommitId) do={
$LogPrint info $0 ("Updated to commit: " . $CommitInfo . "/" . [ :pick $CommitId 0 8 ]);
}
:if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={
$LogPrint warning $0 ("The configuration version decreased from " . \
$ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \
@ -1679,7 +1721,17 @@
:delay $Delay;
:set I ($I + 1);
}
:return true;
:while ([ :len [ /file/find where name=$FileName ] ] > 0) do={
:do {
/file/get $FileName;
:return true;
} on-error={ }
:delay $Delay;
:set Delay ($Delay * 3 / 2);
}
:return false;
}
# wait to be fully connected (default route is reachable, time is sync, DNS resolves)

View file

@ -20,7 +20,9 @@
:global ScriptLock;
:local NaAddress $"na-address";
:local NaValid $"na-valid";
:local PdPrefix $"pd-prefix";
:local PdValid $"pd-valid";
:if ([ $ScriptLock $ScriptName ] = false) do={
:set ExitOK true;
@ -33,12 +35,18 @@
: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.");
:set ExitOK true;
: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 ];
: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;

View file

@ -57,6 +57,11 @@
:local MessageVal;
:local MessageDups ({});
:set LogForwardFilter [ $EitherOr $LogForwardFilter [] ];
:set LogForwardFilterMessage [ $EitherOr $LogForwardFilterMessage [] ];
:set LogForwardInclude [ $EitherOr $LogForwardInclude [] ];
:set LogForwardIncludeMessage [ $EitherOr $LogForwardIncludeMessage [] ];
:local LogForwardFilterLogForwardingCached [ $EitherOr [ $LogForwardFilterLogForwarding ] ("\$^") ];
:foreach Message in=[ /log/find where (!(message="") and \
!(message~$LogForwardFilterLogForwardingCached) and \

View file

@ -10,6 +10,7 @@
# https://rsc.eworm.de/doc/mod/notification-telegram.md
:global FlushTelegramQueue;
:global GetTelegramChatId;
:global NotificationFunctions;
:global PurgeTelegramQueue;
:global SendTelegram;
@ -22,7 +23,6 @@
:global IsFullyConnected;
:global LogPrint;
:global UrlEncode;
:if ([ $IsFullyConnected ] = false) do={
$LogPrint debug $0 ("System is not fully connected, not flushing.");
@ -41,9 +41,7 @@
:do {
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \
http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \
"&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \
"&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data");
http-data=($Message->"http-data") as-value ]->"data");
:set ($TelegramQueue->$Id);
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
} on-error={
@ -61,6 +59,45 @@
:global ExitError; $ExitError false $0;
} }
# get the chat id
:set GetTelegramChatId do={ :do {
: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;
:do {
: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");
} on-error={
$LogPrint warning $0 ("Fetching data failed!");
: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"));
}
} on-error={
:global ExitError; $ExitError false $0;
} }
# send notification via telegram - expects one array argument
:set ($NotificationFunctions->"telegram") do={
:local Notification $1;
@ -71,6 +108,8 @@
:global TelegramChatIdOverride;
:global TelegramMessageIDs;
:global TelegramQueue;
:global TelegramThreadId;
:global TelegramThreadIdOverride;
:global TelegramTokenId;
:global TelegramTokenIdOverride;
@ -111,6 +150,8 @@
:local ChatId [ $EitherOr ($Notification->"chatid") \
[ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ];
:local ThreadId [ $EitherOr ($Notification->"threadid") \
[ $EitherOr ($TelegramThreadIdOverride->($Notification->"origin")) $TelegramThreadId ] ];
:local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ];
:if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={
@ -145,6 +186,9 @@
(($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]);
}
:local HTTPData ("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
"&reply_to_message_id=" . ($Notification->"replyto") . "&message_thread_id=" . $ThreadId . \
"&disable_web_page_preview=true&parse_mode=MarkdownV2");
:do {
:if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={
$LogPrint warning $0 ("Downloading required certificate failed.");
@ -152,9 +196,7 @@
}
:local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \
("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \
http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \
"&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \
"&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) as-value ]->"data");
:set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1;
} on-error={
$LogPrint info $0 ("Failed sending Telegram notification! Queuing...");
@ -165,8 +207,8 @@
:set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \
[ $EscapeMD ("This message was queued since _" . [ /system/clock/get date ] . \
" " . [ /system/clock/get time ] . "_ and may be obsolete.") "plain" "_" ]);
:set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId;
text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") };
:set ($TelegramQueue->[ :len $TelegramQueue ]) { tokenid=$TokenId;
http-data=($HTTPData . "&text=" . [ $UrlEncode $Text ]) };
:if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={
/system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \
on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;");

View file

@ -4,7 +4,6 @@
# https://rsc.eworm.de/COPYING.md
#
# requires RouterOS, version=7.15
# requires device-mode, fetch
#
# download script and run it once
# https://rsc.eworm.de/doc/mod/scriptrunonce.md
@ -18,6 +17,7 @@
:global ScriptRunOnceBaseUrl;
:global ScriptRunOnceUrlSuffix;
:global FetchHuge;
:global LogPrint;
:global ValidateSyntax;
@ -30,25 +30,26 @@
:set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix);
}
:local Source;
:do {
:set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data");
} on-error={
:local Source [ $FetchHuge $0 $Script true ];
:if ($Source = false) do={
$LogPrint warning $0 ("Failed fetching script '" . $Script . "'!");
:return false;
}
:if ([ :len $Source ] > 0) do={
:if ([ $ValidateSyntax $Source ] = true) do={
:do {
$LogPrint info $0 ("Running script '" . $Script . "' now.");
[ :parse $Source ];
} on-error={
$LogPrint warning $0 ("The script '" . $Script . "' failed to run!");
}
} else={
$LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!");
}
:if ([ $ValidateSyntax $Source ] = false) do={
$LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!");
:return false;
}
:do {
$LogPrint info $0 ("Running script '" . $Script . "' now.");
[ :parse $Source ];
} on-error={
$LogPrint warning $0 ("The script '" . $Script . "' failed to run!");
:return false;
}
:return true;
}
} on-error={
:global ExitError; $ExitError false $0;

View file

@ -61,15 +61,19 @@
:global GetRandom20CharAlNum;
:local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]);
/ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s;
:delay 20ms;
:if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
:return true;
:if ([ :typeof [ :toip $Expected ] ] = "ip") do={
/ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s;
:delay 20ms;
: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;
:delay 20ms;
:if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
:return true;
:if ([ :typeof [ :toip6 $Expected ] ] = "ip6") do={
/ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=10s;
:delay 20ms;
:if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={
:return true;
}
}
:return false;

View file

@ -57,6 +57,9 @@
130="Dropped intermediate certificates, depending on just root certificates now.";
131="Enhanced certificate download to fallback to mkcert.org, so all (commonly trusted) root certificates are available now.";
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.";
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.";
};
# Migration steps to be applied on script updates

View file

@ -97,13 +97,14 @@
:foreach Update in=($JSON->"result") do={
:set UpdateID ($Update->"update_id");
:local Message ($Update->"message");
:local IsReply [ :len ($Message->"reply_to_message") ];
:local IsReply ([ :typeof ($Message->"reply_to_message") ] = "string");
:local IsMyReply ($TelegramMessageIDs->[ :tostr ($Message->"reply_to_message"->"message_id") ]);
:if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={
:local Trusted false;
:local Chat ($Message->"chat");
:local From ($Message->"from");
:local Command ($Message->"text");
:local ThreadId [ $IfThenElse ($Message->"is_topic_message") ($Message->"message_thread_id") "" ];
:foreach IdsTrusted in=($TelegramChatId, $TelegramChatIdsTrusted) do={
:if ($From->"id" = $IdsTrusted || $From->"username" = $IdsTrusted) do={
@ -115,9 +116,11 @@
:local Done false;
:if ($Command = "?") do={
$LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . ".");
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; \
replyto=($Message->"message_id"); threadid=$ThreadId; \
subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \
message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") });
message=([ $IfThenElse ([ :len ($From->"first_name") ] > 0) ("Hello " . ($From->"first_name") . "!\n\n") ] . \
"Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") });
:set Done true;
}
:if ($Done = false && [ :pick $Command 0 1 ] = "!") do={
@ -130,7 +133,8 @@
" from update " . $UpdateID . "!");
:set Done true;
}
:if ($Done = false && ($IsMyReply = 1 || ($IsReply = 0 && $TelegramChatActive = true)) && [ :len $Command ] > 0) do={
:if ($Done = false && ($IsMyReply = 1 || ($IsReply = false && \
$TelegramChatActive = true)) && [ :len $Command ] > 0) do={
:if ([ $ValidateSyntax $Command ] = true) do={
:local State "";
:local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]);
@ -149,7 +153,8 @@
:set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n");
}
:local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data");
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; \
replyto=($Message->"message_id"); threadid=$ThreadId; \
subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \
message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \
$State . [ $IfThenElse ([ :len $Content ] > 0) \
@ -158,7 +163,8 @@
$RmDir "tmpfs/telegram-chat";
} else={
$LogPrint info $ScriptName ("The command from update " . $UpdateID . " failed syntax validation!");
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; \
replyto=($Message->"message_id"); threadid=$ThreadId; \
subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \
message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \
[ $SymbolForNotification "cross-mark" ] . "The command failed syntax validation!") });
@ -170,7 +176,8 @@
" (ID " . $From->"id" . ") in update " . $UpdateID . "!");
:if ($Command ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={
$LogPrint warning $ScriptName $MessageText;
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \
$SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; \
replyto=($Message->"message_id"); threadid=$ThreadId; \
subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \
message=("You are not trusted.") });
} else={