diff --git a/.gitignore b/.gitignore index cf89f87..f29d4e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,3 @@ -# backup and temporary files *~ - -# patches and related files -*.orig *.patch -*.rej - -# html files (as generated from markdown) *.html - -# Mac OS X folder settings file -.DS_Store diff --git a/BRANCHES.md b/BRANCHES.md deleted file mode 100644 index 8a0bdad..0000000 --- a/BRANCHES.md +++ /dev/null @@ -1,50 +0,0 @@ -Installing from branches -======================== - -[![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) - -> ⚠️ **Warning**: Living on the edge? Great, read on! -> If not: Please use the `main` branch and leave this page! - -These scripts are developed in a [git](https://git-scm.com/) repository. -Development and experimental branches are used to provide early access -for specific changes. You can install scripts from these branches -for testing. - -## Install single script - -To install a single script from `next` branch: - - $ScriptInstallUpdate script-name "base-url=https://rsc.eworm.de/next/"; - -## Switch existing script - -Alternatively switch an existing script to update from `next` branch: - - /system/script/set comment="base-url=https://rsc.eworm.de/next/" script-name; - $ScriptInstallUpdate; - -## Switch installation - -Last but not least - to switch the complete installation to the `next` -branch edit `global-config-overlay` and add: - - :global ScriptUpdatesBaseUrl "https://rsc.eworm.de/next/"; - -... then reload the configuration and update: - - /system/script/run global-config; - $ScriptInstallUpdate; - -> ℹ️ **Info**: Replace `next` with *whatever* to use another specific branch. - ---- -[⬅️ Go back to main README](README.md) -[⬆️ Go back to top](#top) diff --git a/CERTIFICATES.d/01-dialog-A.avif b/CERTIFICATES.d/01-dialog-A.avif deleted file mode 100644 index 2fc3c9b..0000000 Binary files a/CERTIFICATES.d/01-dialog-A.avif and /dev/null differ diff --git a/CERTIFICATES.d/02-dialog-B.avif b/CERTIFICATES.d/02-dialog-B.avif deleted file mode 100644 index 5e408ab..0000000 Binary files a/CERTIFICATES.d/02-dialog-B.avif and /dev/null differ diff --git a/CERTIFICATES.d/03-window.avif b/CERTIFICATES.d/03-window.avif deleted file mode 100644 index 96039a3..0000000 Binary files a/CERTIFICATES.d/03-window.avif and /dev/null differ diff --git a/CERTIFICATES.d/04-certificate.avif b/CERTIFICATES.d/04-certificate.avif deleted file mode 100644 index e666314..0000000 Binary files a/CERTIFICATES.d/04-certificate.avif and /dev/null differ diff --git a/CERTIFICATES.md b/CERTIFICATES.md deleted file mode 100644 index 5432d78..0000000 --- a/CERTIFICATES.md +++ /dev/null @@ -1,82 +0,0 @@ -Certificate name from browser -============================= - -[![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) - -All well known desktop, mobile and server operating systems come with a -certificate store that is populated with a set of well known and trusted -certificates, acting as *trust anchors*. - -However RouterOS does not, still sometimes a specific certificate is -required to properly verify a chain of trust. One example is downloading -the scripts from this repository with `fetch` command, thus the very -first step of [installation](README.md#the-long-way-in-detail) is importing -the certificate. - -The scripts can install additional certificates when required. This happens -from this repository if available, or from [mkcert.org](https://mkcert.org) -as a fallback. - -Get the certificate's CommonName --------------------------------- - -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 -[Mozilla Firefox](https://www.mozilla.org/firefox/). - -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 -browser, then click the *lock* icon in addressbar, followed by "*Connection -secure*". - -![screenshot: dialog A](CERTIFICATES.d/01-dialog-A.avif) - -The dialog will change, click "*More information*". - -![screenshot: dialog B](CERTIFICATES.d/02-dialog-B.avif) - -A new window opens, click the button "*View Certificate*". (That window -can be closed now.) - -![screenshot: window](CERTIFICATES.d/03-window.avif) - -A new tab opens, showing information on the server certificate and its -chain of trust. The leftmost certificate is what we are interested in. - -![screenshot: certificate](CERTIFICATES.d/04-certificate.avif) - -Now we know that "`ISRG Root X2`" is required, some scripts need just -that information. - -Import a certificate by CommonName ----------------------------------- - -Running the function `$CertificateAvailable` with that name as parameter -makes sure the certificate is available in the device's store: - - $CertificateAvailable "ISRG Root X2"; - -If the certificate is actually available already nothing happens, and there -is no output. Otherwise the certificate is downloaded and imported. - -If importing a certificate with that exact name fails a warning is given -and nothing is actually imported. - -See also --------- - -* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) -* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) -* [Send notifications via Matrix](doc/mod/notification-matrix.md) -* [Send notifications via Ntfy](doc/mod/notification-ntfy.md) - ---- -[⬅️ Go back to main README](README.md) -[⬆️ Go back to top](#top) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 0b35c40..a78b0df 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -1,63 +1,29 @@ Past Contributions ================== -[![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) -[⬅️ Go back to main README](README.md) - -Thanks a lot for your contributions! ❤️ +Thanks a lot for your contributions! ## Patches -These persons contributed code or documentation. See the git history -for details! +These persons contributed code. See the git history for details! -* [Anatoly Bubenkov](mailto:bubenkoff@gmail.com) (@bubenkoff) -* [Ben Harris](mailto:mail@bharr.is) (@bharrisau) * [Daniel Ziegenberg](mailto:daniel@ziegenberg.at) (@ziegenberg) -* [Ignacio Serrano](mailto:ignic@ignic.com) (@ignic) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) -* [Miquel Bonastre](mailto:mbonastre@yahoo.com) (@mbonastre) -* @netravnen * [netztrip](mailto:dave-tvg@netztrip.de) (@netztrip) -* [Stefan Müller](mailto:stefan.mueller.83@gmail.com) (@PackElend) ## Donations Add yourself to the list, [donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! -* Abdul Mannan Abbasi -* Andrea Ruffini Perico -* Andrew Cox * Christoph Boss (@Kampfwurst) -* Daniel Ziegenberg (@ziegenberg) -* Devin Dean (@dd2594gh) -* Evaldo Gardenal -* Florian Estraviz -* Giorgio Bikos -* Harold Schoemaker -* Hugo BV * Klaus Michael Rübsam -* Leonardo Valeri Manera * Linux-Schmie.de Michael Gisbers -* Manuel Kuhn * Marek Čábák -* Oleksandr Yukhymchuk -* Peter Holtkamp -* Peter Ponzel * Reiner Vehrenkamp -* Richard Österreicher -* Simon Hitzemann -* Sunny Chu (@sunnychuchu) -* Ulrich Wessendorf -* Zac Kornilakis --- -[⬅️ Go back to main README](README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](README.md) +[▲ Go back to top](#top) diff --git a/DEBUG.md b/DEBUG.md deleted file mode 100644 index d5e9beb..0000000 --- a/DEBUG.md +++ /dev/null @@ -1,63 +0,0 @@ -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) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 8b64d28..9a5d6c8 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -1,53 +1,35 @@ Initial commands ================ -[![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) -[⬅️ Go back to main README](README.md) - -> ⚠️ **Warning**: These command are inteneded for initial setup. If you are -> not aware of the procedure please follow -> [the long way in detail](README.md#the-long-way-in-detail). - -Run the complete base installation: +These command are inteneded for initial setup. If you are not aware of the +procedure please follow [the long way in detail](README.md#the-long-way-in-detail). { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem" as-value; + / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem"; :delay 1s; - /certificate/import file-name="isrg-root-x2.pem" passphrase=""; - :if ([ :len [ /certificate/find where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 1) do={ + / certificate import file-name=letsencrypt-R3.pem passphrase=""; + :if ([ :len [ / certificate find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] ] != 3) do={ :error "Something is wrong with your certificates!"; - }; - :delay 1s; - /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; + } + / file remove "letsencrypt-R3.pem"; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - /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 { run global-config; run global-functions; }; - /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 script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); + } + / system script set comment="ignore" global-config-overlay; + / system script { run global-config; run global-config-overlay; run global-functions; } + / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }"; :global CertificateNameByCN; - $CertificateNameByCN "ISRG Root X2"; - }; + $CertificateNameByCN "R3"; + $CertificateNameByCN "ISRG Root X1"; + $CertificateNameByCN "DST Root CA X3"; + } -Then continue setup with -[scheduled automatic updates](README.md#scheduled-automatic-updates) or -[editing configuration](README.md#editing-configuration). +Optional to update the scripts automatically: -## Fix existing installation - -The [initial commands](#initial-commands) above allow to fix an existing -installation in case it ever breaks. If `global-config-overlay` did exist -before it is renamed with a date and time suffix (like -`global-config-overlay-2024-01-25-09:33:12`). Make sure to restore the -configuration overlay if required. + / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; --- -[⬅️ Go back to main README](README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](README.md) +[▲ Go back to top](#top) diff --git a/Makefile b/Makefile index d21713c..f96e73e 100644 --- a/Makefile +++ b/Makefile @@ -2,35 +2,24 @@ # template scripts -> final scripts # markdown files -> html files -CAPSMAN = $(wildcard *.capsman.rsc) -LOCAL = $(wildcard *.local.rsc) -WIFI = $(wildcard *.wifi.rsc) +TEMPLATE = $(wildcard *.template) +CAPSMAN = $(TEMPLATE:.template=.capsman) +LOCAL = $(TEMPLATE:.template=.local) -MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) -HTML = $(MARKDOWN:.md=.html) +MARKDOWN = $(wildcard *.md) +HTML = $(MARKDOWN:.md=.html) -all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML) +all: $(CAPSMAN) $(LOCAL) $(HTML) %.html: %.md Makefile - markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ + markdown $< | sed 's/href="\([-[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ -%.capsman.rsc: %.template.rsc Makefile - sed -e '/\/interface\/wifi\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.capsman|' \ - -e '/^# NOT \/caps-man\/ #$$/,/^# NOT \/caps-man\/ #$$/d' \ +%.local: %.template Makefile + sed -e '/\/ caps-man/d' -e 's|%PATH%|interface wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ -%.local.rsc: %.template.rsc Makefile - sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e 's|%TEMPL%|.local|' \ - -e '/^# NOT \/interface\/wireless\/ #$$/,/^# NOT \/interface\/wireless\/ #$$/d' \ +%.capsman: %.template Makefile + sed -e '/\/ interface wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ - -%.wifi.rsc: %.template.rsc Makefile - sed -e '/\/caps-man\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifi|' \ - -e '/^# NOT \/interface\/wifi\/ #$$/,/^# NOT \/interface\/wifi\/ #$$/d' \ - -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ - < $< > $@ - -clean: - rm -f $(HTML) diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif deleted file mode 100644 index d41ca05..0000000 Binary files a/README.d/01-download-certs.avif and /dev/null differ diff --git a/README.d/02-import-certs.avif b/README.d/02-import-certs.avif deleted file mode 100644 index bf7d577..0000000 Binary files a/README.d/02-import-certs.avif and /dev/null differ diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif deleted file mode 100644 index 4717b3e..0000000 Binary files a/README.d/03-check-certs.avif and /dev/null differ diff --git a/README.d/04-import-scripts.avif b/README.d/04-import-scripts.avif deleted file mode 100644 index 53439e4..0000000 Binary files a/README.d/04-import-scripts.avif and /dev/null differ diff --git a/README.d/05-run-and-schedule-scripts.avif b/README.d/05-run-and-schedule-scripts.avif deleted file mode 100644 index 37e1173..0000000 Binary files a/README.d/05-run-and-schedule-scripts.avif and /dev/null differ diff --git a/README.d/06-schedule-update.avif b/README.d/06-schedule-update.avif deleted file mode 100644 index 7c96f3a..0000000 Binary files a/README.d/06-schedule-update.avif and /dev/null differ diff --git a/README.d/07-edit-global-config-overlay.avif b/README.d/07-edit-global-config-overlay.avif deleted file mode 100644 index f87fda8..0000000 Binary files a/README.d/07-edit-global-config-overlay.avif and /dev/null differ diff --git a/README.d/08-apply-configuration.avif b/README.d/08-apply-configuration.avif deleted file mode 100644 index b66af1a..0000000 Binary files a/README.d/08-apply-configuration.avif and /dev/null differ diff --git a/README.d/09-update-scripts.avif b/README.d/09-update-scripts.avif deleted file mode 100644 index f549fef..0000000 Binary files a/README.d/09-update-scripts.avif and /dev/null differ diff --git a/README.d/10-install-scripts.avif b/README.d/10-install-scripts.avif deleted file mode 100644 index 00225b1..0000000 Binary files a/README.d/10-install-scripts.avif and /dev/null differ diff --git a/README.d/11-schedule-script.avif b/README.d/11-schedule-script.avif deleted file mode 100644 index d6eb0f8..0000000 Binary files a/README.d/11-schedule-script.avif and /dev/null differ diff --git a/README.d/12-setup-lease-script.avif b/README.d/12-setup-lease-script.avif deleted file mode 100644 index fb4024e..0000000 Binary files a/README.d/12-setup-lease-script.avif and /dev/null differ diff --git a/README.d/13-install-custom-script.avif b/README.d/13-install-custom-script.avif deleted file mode 100644 index 2f01c43..0000000 Binary files a/README.d/13-install-custom-script.avif and /dev/null differ diff --git a/README.d/14-remove-script.avif b/README.d/14-remove-script.avif deleted file mode 100644 index a5c7daf..0000000 Binary files a/README.d/14-remove-script.avif and /dev/null differ diff --git a/README.d/hello-world.rsc b/README.d/hello-world.rsc deleted file mode 100644 index 6404781..0000000 --- a/README.d/hello-world.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS - -:put ("Hello World from " . [ /system/identity/get name ] . "!"); diff --git a/README.d/notification-news-and-changes.avif b/README.d/notification-news-and-changes.avif deleted file mode 100644 index d91b8a0..0000000 Binary files a/README.d/notification-news-and-changes.avif and /dev/null differ diff --git a/README.d/telegram-group.avif b/README.d/telegram-group.avif deleted file mode 100644 index eb75d13..0000000 Binary files a/README.d/telegram-group.avif and /dev/null differ diff --git a/README.d/upstream.png b/README.d/upstream.png deleted file mode 100644 index fd5e877..0000000 Binary files a/README.d/upstream.png and /dev/null differ diff --git a/README.md b/README.md index fae6986..448cb10 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,9 @@ RouterOS Scripts ================ -[![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) - -![RouterOS Scripts Logo](logo.svg) +[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) +[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/stargazers) +[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) [RouterOS](https://mikrotik.com/software) is the operating system developed by [MikroTik](https://mikrotik.com/aboutus) for networking tasks. This @@ -21,33 +16,11 @@ to manage RouterOS devices or extend their functionality. Requirements ------------ -### Software (RouterOS) - Latest version of the scripts require recent RouterOS to function properly. -Make sure to install latest updates before you begin. If new functionality -or a breaking change in RouterOS `7.n` is used in my scripts I push my -change some time after `7.(n+1)` was released. At any time you should have -at least two minor and their bugfix releases to choose from. +Make sure to install latest updates before you begin. Specific scripts may require even newer RouterOS version. -> ℹ️ **Info**: The `main` branch is now RouterOS v7 only. If you are still -> running RouterOS v6 switch to `routeros-v6` branch! - -Starting with RouterOS 7.17 the -[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 -available. You need to enable `scheduler` and `fetch` at least, specific -scripts may require additional features. - -### Hardware - -RouterOS packages increase in size with each release. This becomes a -problem for devices with 16MB storage and below, those with an ARM CPU -are specifically affected. - -Huge configuration and lots of scripts give an extra risk. **Take care!** - Initial setup ------------- @@ -65,8 +38,8 @@ RouterOS script distribution](https://www.youtube.com/watch?v=B9neG3oAhcY) including demonstation recorded live at [MUM Europe 2019](https://mum.mikrotik.com/2019/EU/) in Vienna. -> ⚠️ **Warning**: Some details changed. So see the presentation, then follow -> the steps below for up-to-date commands. +*Be warned!* Some details changed. So see the presentation, then follow +the steps below for up-to-date commands. ### The long way in detail @@ -75,107 +48,76 @@ download the certificates. If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem"; - -![screenshot: download certs](README.d/01-download-certs.avif) + [admin@MikroTik] > / tool fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" + status: finished + downloaded: 4KiBC-z pause] + total: 4KiB + duration: 1s 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 -file to your MikroTik device. +files to your MikroTik device. -* [ISRG Root X2](https://letsencrypt.org/certs/isrg-root-x2.pem) +* [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) +* Let's Encrypt [R3](https://letsencrypt.org/certs/lets-encrypt-r3.pem) -Then we import the certificate. +Then we import the certificates. - /certificate/import file-name="isrg-root-x2.pem" passphrase=""; + [admin@MikroTik] > / certificate import file-name=letsencrypt-R3.pem passphrase="" + certificates-imported: 3 + private-keys-imported: 0 + files-imported: 1 + decryption-failures: 0 + keys-with-no-certificate: 0 -Do not worry that the command is not shown - that happens because it contains -a sensitive property, the passphrase. +For basic verification we rename the certifiactes and print their count. Make +sure the certificate count is **three**. -![screenshot: import certs](README.d/02-import-certs.avif) - -For basic verification we rename the certificate and print it by -fingerprint. Make sure exactly this one certificate ("*ISRG-Root-X2*") -is shown. - - /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; - /certificate/print proplist=name,fingerprint where fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; - -![screenshot: check certs](README.d/03-check-certs.avif) + [admin@MikroTik] > / certificate set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ] + [admin@MikroTik] > / certificate set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] + [admin@MikroTik] > / certificate set name="DST-Root-CA-X3" [ find where fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" ] + [admin@MikroTik] > / certificate print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" or fingerprint="0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739" + 3 Always make sure there are no certificates installed you do not know or want! -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 -date and time is set correctly! +Actually we do not require the certificate named `DST Root CA X3`, but as it +is used by `Let's Encrypt` to cross-sign we install it anyway - this makes +sure things do not go wrong if the intermediate certificate is replaced. +The IdenTrust certificate *should* be available from their +[download page](https://www.identrust.com/support/downloads). The site is +crap and a good example how to *not* do it. Now let's download the main scripts and add them in configuration on the fly. - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script 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"); }; + [admin@MikroTik] > :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ / system script add name=$Script source=([ / tool fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); } -![screenshot: import scripts](README.d/04-import-scripts.avif) +Mark `global-config-overlay` not to be overwritten by future updates. + + [admin@MikroTik] > / system script set comment="ignore" global-config-overlay + +The configuration needs to be tweaked for your needs. Edit +`global-config-overlay`, copy configuration from +[`global-config`](global-config) (the one without `-overlay`). + + [admin@MikroTik] > / system script edit global-config-overlay source And finally load configuration and functions and add the scheduler. - /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; }"; + [admin@MikroTik] > / system script { run global-config; run global-config-overlay; run global-functions; } + [admin@MikroTik] > / system scheduler add name="global-scripts" start-time=startup on-event="/ system script { run global-config; run global-config-overlay; run global-functions; }" -![screenshot: run and schedule scripts](README.d/05-run-and-schedule-scripts.avif) +The last step is optional: Add this scheduler **only** if you want the scripts +to be updated automatically! -### Scheduled automatic updates - -The last step is optional: Add this scheduler **only** if you want the -scripts to be updated automatically! - - /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; - -![screenshot: schedule update](README.d/06-schedule-update.avif) - -Editing configuration ---------------------- - -The configuration needs to be tweaked for your needs. Edit -`global-config-overlay`, copy relevant configuration from -[`global-config`](global-config.rsc) (the one without `-overlay`). -Save changes and exit with `Ctrl-o`. - - /system/script/edit global-config-overlay source; - -![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif) - -Additionally creating configuration snippets is supported. The script name -of these snippets has to start with `global-config-overlay.d/` to make them -being loaded automatically. This allows to split off parts of the -configuration. - -To apply your changes run `global-config`, which will automatically load -the overlay as well: - - /system/script/run global-config; - -![screenshot: apply configuration](README.d/08-apply-configuration.avif) - -This last step is required when ever you make changes to your configuration. - -> ℹ️ **Info**: It is recommended to edit the configuration using the command -> line interface. If using Winbox on Windows OS, the line endings may be -> missing. To fix this run: -> `/system/script/set source=[ :tocrlf [ get global-config-overlay source ] ] global-config-overlay;` + [admin@MikroTik] > / system scheduler add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;" Updating scripts ---------------- -To update existing scripts just run function `$ScriptInstallUpdate`. If -everything is up-to-date it will not produce any output. +To update existing scripts just run function `$ScriptInstallUpdate`. - $ScriptInstallUpdate; - -![screenshot: update scripts](README.d/09-update-scripts.avif) - -If the update includes news or requires configuration changes a notification -is sent - in addition to terminal output and log messages. - -![news and changes notification](README.d/notification-news-and-changes.avif) + [admin@MikroTik] > $ScriptInstallUpdate Adding a script --------------- @@ -183,42 +125,33 @@ Adding a script To add a script from the repository run function `$ScriptInstallUpdate` with a comma separated list of script names. - $ScriptInstallUpdate check-certificates,check-routeros-update; - -![screenshot: install scripts](README.d/10-install-scripts.avif) + [admin@MikroTik] > $ScriptInstallUpdate check-certificates,check-routeros-update Scheduler and events -------------------- Most scripts are designed to run regularly from [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 every hour to make sure not to miss an update. - /system/scheduler/add name="check-routeros-update" interval=1d start-time=startup on-event="/system/script/run check-routeros-update;"; - -![screenshot: schedule script](README.d/11-schedule-script.avif) + [admin@MikroTik] > / system scheduler add name="check-routeros-update" interval=1h on-event="/ system script run check-routeros-update;" Some events can run a script. If you want your DHCP hostnames to be available in DNS use `dhcp-to-dns` with the events from dhcp server. For a regular cleanup add a scheduler entry. - $ScriptInstallUpdate dhcp-to-dns,lease-script; - /ip/dhcp-server/set lease-script=lease-script [ find ]; - /system/scheduler/add name="dhcp-to-dns" interval=5m on-event="/system/script/run dhcp-to-dns;"; - -![screenshot: setup lease script](README.d/12-setup-lease-script.avif) + [admin@MikroTik] > $ScriptInstallUpdate dhcp-to-dns,lease-script + [admin@MikroTik] > / ip dhcp-server set lease-script=lease-script [ find ] + [admin@MikroTik] > / system scheduler add name="dhcp-to-dns" interval=5m on-event="/ system script run dhcp-to-dns;" There's much more to explore... Have fun! -Available scripts +Available Scripts ----------------- * [Find and remove access list duplicates](doc/accesslist-duplicates.md) -* [Upload backup to Mikrotik cloud](doc/backup-cloud.md) -* [Send backup via e-mail](doc/backup-email.md) -* [Save configuration to fallback partition](doc/backup-partition.md) -* [Upload backup to server](doc/backup-upload.md) +* [Manage ports in bridge](doc/bridge-port.md) * [Download packages for CAP upgrade from CAPsMAN](doc/capsman-download-packages.md) * [Run rolling CAP upgrades from CAPsMAN](doc/capsman-rolling-upgrade.md) * [Renew locally issued certificates](doc/certificate-renew-issued.md) @@ -226,122 +159,49 @@ Available scripts * [Notify about health state](doc/check-health.md) * [Notify on LTE firmware upgrade](doc/check-lte-firmware-upgrade.md) * [Notify on RouterOS update](doc/check-routeros-update.md) +* [Upload backup to Mikrotik cloud](doc/cloud-backup.md) * [Collect MAC addresses in wireless access list](doc/collect-wireless-mac.md) * [Use wireless network with daily psk](doc/daily-psk.md) * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) -* [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md) -* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) -* [Wait for global functions und modules](doc/global-wait.md) +* [Send backup via e-mail](doc/email-backup.md) +* [Wait for configuration und functions](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) -* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) -* [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) +* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) * [Run other scripts on DHCP lease](doc/lease-script.md) * [Manage LEDs dark mode](doc/leds-mode.md) * [Forward log messages via notification](doc/log-forward.md) * [Mode button with multiple presses](doc/mode-button.md) -* [Manage DNS and DoH servers from netwatch](doc/netwatch-dns.md) * [Notify on host up and down](doc/netwatch-notify.md) +* [Manage remote logging](doc/netwatch-syslog.md) * [Visualize OSPF state via LEDs](doc/ospf-to-leds.md) * [Manage system update](doc/packages-update.md) * [Run scripts on ppp connection](doc/ppp-on-up.md) +* [Rotate NTP servers](doc/rotate-ntp.md) * [Act on received SMS](doc/sms-action.md) * [Forward received SMS](doc/sms-forward.md) +* [Import SSH keys](doc/ssh-keys-import.md) * [Play Super Mario theme](doc/super-mario-theme.md) -* [Chat with your router and send commands via Telegram bot](doc/telegram-chat.md) * [Install LTE firmware upgrade](doc/unattended-lte-firmware-upgrade.md) * [Update GRE configuration with dynamic addresses](doc/update-gre-address.md) * [Update tunnelbroker configuration](doc/update-tunnelbroker.md) +* [Upload backup to server](doc/upload-backup.md) -Available modules ------------------ - -* [Manage ports in bridge](doc/mod/bridge-port-to.md) -* [Manage VLANs on bridge ports](doc/mod/bridge-port-vlan.md) -* [Inspect variables](doc/mod/inspectvar.md) -* [IP address calculation](doc/mod/ipcalc.md) -* [Send notifications via e-mail](doc/mod/notification-email.md) -* [Send notifications via Matrix](doc/mod/notification-matrix.md) -* [Send notifications via Ntfy](doc/mod/notification-ntfy.md) -* [Send notifications via Telegram](doc/mod/notification-telegram.md) -* [Download script and run it once](doc/mod/scriptrunonce.md) -* [Import ssh keys for public key authentication](doc/mod/ssh-keys-import.md) - -Installing custom scripts & modules ------------------------------------ - -My scripts cover a lot of use cases, but you may have your own ones. You can -still use my scripts to manage and deploy yours, by specifying `base-url` -(and `url-suffix`) for each script. - -This will fetch and install a script `hello-world.rsc` from the given url: - - $ScriptInstallUpdate hello-world "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/"; - -![screenshot: install custom script](README.d/13-install-custom-script.avif) - -For a script to be considered valid it has to begin with a *magic token*. -Have a look at [any script](README.d/hello-world.rsc) and copy the first line -without modification. - -Starting a script's name with `mod/` makes it a module and it is run -automatically by `global-functions`. - -### Linked custom scripts & modules - -> ⚠️ **Warning**: These links are being provided for your convenience only; -> they do not constitute an endorsement or an approval by me. I bear no -> responsibility for the accuracy, legality or content of the external site -> or for that of subsequent links. Contact the external site for answers to -> questions regarding its content. - -* [Hello World](https://git.eworm.de/cgit/routeros-scripts-custom/about/doc/hello-world.md) - (This is a demo script to show how the linking to external documentation - will be done.) - -> ℹ️ **Info**: You have your own set of scripts and/or modules and want these -> to be listed here? There should be a general info page that links here, -> and documentation for each script. You can start by cloning my -> [Custom RouterOS-Scripts](https://git.eworm.de/cgit/routeros-scripts-custom/) -> (or fork on [GitHub](https://github.com/eworm-de/routeros-scripts-custom) -> or [GitLab](https://gitlab.com/eworm-de/routeros-scripts-custom)) and make -> your changes. Then please [get in contact](#patches-issues-and-whishlist)... - -Removing a script ------------------ - -There is no specific function for script removal. Just remove it from -configuration... - - /system/script/remove to-be-removed; - -![screenshot: remove script](README.d/14-remove-script.avif) - -Possibly a scheduler and other configuration has to be removed as well. - -Contact -------- - -We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)! - -[![RouterOS Scripts Telegram Group](README.d/telegram-group.avif)](https://t.me/routeros_scripts) - -Get help, give feedback or just chat - but do not expect free professional -support! +[comment]: # (TODO: currently undocumented) +[comment]: # (* learn-mac-based-vlan) +[comment]: # (* manage-umts) Contribute ---------- -Thanks a lot for [past contributions](CONTRIBUTIONS.md)! ❤️ +Thanks a lot for [past contributions](CONTRIBUTIONS.md)! ### Patches, issues and whishlist Feel free to contact me via e-mail or open an -[issue](https://github.com/eworm-de/routeros-scripts/issues) or -[pull request](https://github.com/eworm-de/routeros-scripts/pulls) -at github. +[issue at github](https://github.com/eworm-de/routeros-scripts/issues). ### Donate @@ -350,7 +210,7 @@ for you. If you like the scripts and think this is of value for you or your 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://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=for-the-badge)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) +[![donate with PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) Thanks a lot for your support! @@ -370,8 +230,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Upstream -------- -[![upstream](README.d/upstream.png)](https://rsc.eworm.de/) - URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) @@ -380,4 +238,4 @@ Mirror: [GitLab.com](https://gitlab.com/eworm-de/routeros-scripts#routeros-scripts) --- -[⬆️ Go back to top](#top) +[▲ Go back to top](#top) diff --git a/accesslist-duplicates.capsman b/accesslist-duplicates.capsman new file mode 100644 index 0000000..4911760 --- /dev/null +++ b/accesslist-duplicates.capsman @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.capsman +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local Seen [ :toarray "" ]; +:local Shown [ :toarray "" ]; + +:foreach AccList in=[ / caps-man access-list find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ / caps-man access-list get $AccList mac-address ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + / caps-man access-list print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove ([ :terminal inkey ] - 48); + :if ($Remove >= 0 && $Remove <= 9) do={ + :put ("Removing numeric id " . $Remove . "...\n"); + / caps-man access-list remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc deleted file mode 100644 index 27546c8..0000000 --- a/accesslist-duplicates.capsman.rsc +++ /dev/null @@ -1,37 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# print duplicate antries in wireless access list -# https://rsc.eworm.de/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :local Seen ({}); - - :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 ]; - :if ($Seen->$Mac = 1) do={ - /caps-man/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; - - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - } - } - :set ($Seen->$Mac) 1; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local new file mode 100644 index 0000000..84fafb3 --- /dev/null +++ b/accesslist-duplicates.local @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.local +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! Do not edit this file, it is generated from template! + +:local Seen [ :toarray "" ]; +:local Shown [ :toarray "" ]; + +:foreach AccList in=[ / interface wireless access-list find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ / interface wireless access-list get $AccList mac-address ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + / interface wireless access-list print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove ([ :terminal inkey ] - 48); + :if ($Remove >= 0 && $Remove <= 9) do={ + :put ("Removing numeric id " . $Remove . "...\n"); + / interface wireless access-list remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc deleted file mode 100644 index 589815d..0000000 --- a/accesslist-duplicates.local.rsc +++ /dev/null @@ -1,37 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# print duplicate antries in wireless access list -# https://rsc.eworm.de/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :local Seen ({}); - - :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 ]; - :if ($Seen->$Mac = 1) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; - - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; - } - } - :set ($Seen->$Mac) 1; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template new file mode 100644 index 0000000..7161992 --- /dev/null +++ b/accesslist-duplicates.template @@ -0,0 +1,37 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates%TEMPL% +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man' +# !! or 'interface wireless'! + +:local Seen [ :toarray "" ]; +:local Shown [ :toarray "" ]; + +:foreach AccList in=[ / %PATH% access-list find where mac-address!="00:00:00:00:00:00" ] do={ + :local Mac [ / %PATH% access-list get $AccList mac-address ]; + :foreach SeenMac in=$Seen do={ + :if ($SeenMac = $Mac) do={ + :local Skip 0; + :foreach ShownMac in=$Shown do={ + :if ($ShownMac = $Mac) do={ :set Skip 1; } + } + :if ($Skip = 0) do={ + / %PATH% access-list print where mac-address=$Mac; + :set Shown ($Shown, $Mac); + + :put "\nNumeric id to remove, any key to skip!"; + :local Remove ([ :terminal inkey ] - 48); + :if ($Remove >= 0 && $Remove <= 9) do={ + :put ("Removing numeric id " . $Remove . "...\n"); + / %PATH% access-list remove $Remove; + } + } + } + } + :set Seen ($Seen, $Mac); +} diff --git a/accesslist-duplicates.template.rsc b/accesslist-duplicates.template.rsc deleted file mode 100644 index ccbca3d..0000000 --- a/accesslist-duplicates.template.rsc +++ /dev/null @@ -1,46 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# print duplicate antries in wireless access list -# https://rsc.eworm.de/doc/accesslist-duplicates.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :local Seen ({}); - - :foreach AccList in=[ /caps-man/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={ - :foreach AccList in=[ /interface/wireless/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 [ /interface/wifi/access-list/get $AccList mac-address ]; - :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :if ($Seen->$Mac = 1) do={ - /caps-man/access-list/print where mac-address=$Mac; - /interface/wifi/access-list/print where mac-address=$Mac; - /interface/wireless/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; - - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - /interface/wifi/access-list/remove $Remove; - /interface/wireless/access-list/remove $Remove; - } - } - :set ($Seen->$Mac) 1; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc deleted file mode 100644 index 527ebb4..0000000 --- a/accesslist-duplicates.wifi.rsc +++ /dev/null @@ -1,37 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.wifi -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# print duplicate antries in wireless access list -# https://rsc.eworm.de/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :local Seen ({}); - - :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 ]; - :if ($Seen->$Mac = 1) do={ - /interface/wifi/access-list/print where mac-address=$Mac; - :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; - - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wifi/access-list/remove $Remove; - } - } - :set ($Seen->$Mac) 1; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/backup-cloud.rsc b/backup-cloud.rsc deleted file mode 100644 index c4e23b2..0000000 --- a/backup-cloud.rsc +++ /dev/null @@ -1,104 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-cloud -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: backup-script, order=40 -# requires RouterOS, version=7.15 -# -# upload backup to MikroTik cloud -# https://rsc.eworm.de/doc/backup-cloud.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global BackupRandomDelay; - :global Identity; - :global PackagesUpdateBackupFailure; - - :global DeviceInfo; - :global FormatLine; - :global HumanReadableNum; - :global LogPrint; - :global MkDir; - :global RandomDelay; - :global RmDir; - :global ScriptFromTerminal; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; - } - - :if ([ $MkDir ("tmpfs/backup-cloud") ] = false) do={ - $LogPrint error $ScriptName ("Failed creating directory!"); - :set ExitOK true; - :error false; - } - - :local I 5; - :do { - :execute { - :global BackupPassword; - - :local Backup ([ /system/backup/cloud/find ]->0); - :if ([ :typeof $Backup ] = "id") do={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=$Backup; - } else={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword; - } - /file/add name="tmpfs/backup-cloud/done"; - } as-string; - :set I ($I - 1); - } while=([ $WaitForFile "tmpfs/backup-cloud/done" 200ms ] = false && $I > 0); - - :if ([ $WaitForFile "tmpfs/backup-cloud/done" ] = true) do={ - :if ($I < 4) do={ - :log warning ($ScriptName . ": Retry successful, please discard previous connection errors."); - } - - :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; - - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ - message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - [ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ - [ $FormatLine "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "B") ] . "\n" . \ - [ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); - } else={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ - message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrint error $ScriptName ("Failed uploading backup for " . $Identity . " to cloud!"); - :set PackagesUpdateBackupFailure true; - } - $RmDir "tmpfs/backup-cloud"; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/backup-email.rsc b/backup-email.rsc deleted file mode 100644 index d097301..0000000 --- a/backup-email.rsc +++ /dev/null @@ -1,140 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-email -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: backup-script, order=20 -# requires RouterOS, version=7.15 -# -# create and email backup and config file -# https://rsc.eworm.de/doc/backup-email.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global BackupPassword; - :global BackupRandomDelay; - :global BackupSendBinary; - :global BackupSendExport; - :global BackupSendGlobalConfig; - :global Domain; - :global Identity; - :global PackagesUpdateBackupFailure; - - :global CleanName; - :global DeviceInfo; - :global FormatLine; - :global LogPrint; - :global MkDir; - :global RandomDelay; - :global ScriptFromTerminal; - :global ScriptLock; - :global SendEMail2; - :global SymbolForNotification; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ :typeof $SendEMail2 ] = "nothing") do={ - $LogPrint error $ScriptName ("The module for sending notifications via e-mail is not installed."); - :set ExitOK true; - :error false; - } - - :if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); - :set ExitOK true; - :error false; - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; - } - - # filename based on identity - :local DirName ("tmpfs/" . $ScriptName); - :local FileName [ $CleanName ($Identity . "." . $Domain) ]; - :local FilePath ($DirName . "/" . $FileName); - :local BackupFile "none"; - :local ExportFile "none"; - :local ConfigFile "none"; - :local Attach ({}); - - :if ([ $MkDir $DirName ] = false) do={ - $LogPrint error $ScriptName ("Failed creating directory!"); - :set ExitOK true; - :error false; - } - - # binary backup - :if ($BackupSendBinary = true) do={ - /system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword; - $WaitForFile ($FilePath . ".backup"); - :set BackupFile ($FileName . ".backup"); - :set Attach ($Attach, ($FilePath . ".backup")); - } - - # create configuration export - :if ($BackupSendExport = true) do={ - /export terse show-sensitive file=$FilePath; - $WaitForFile ($FilePath . ".rsc"); - :set ExportFile ($FileName . ".rsc"); - :set Attach ($Attach, ($FilePath . ".rsc")); - } - - # global-config-overlay - :if ($BackupSendGlobalConfig = true) do={ - # Do *NOT* use '/file/add ...' here, as it is limited to 4095 bytes! - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf\00"); - $WaitForFile ($FilePath . ".conf"); - :set ConfigFile ($FileName . ".conf"); - :set Attach ($Attach, ($FilePath . ".conf")); - } - - # send email with status and files - $SendEMail2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ - "Backup & Config"); \ - message=("See attached files for backup and config export for " . \ - $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - [ $FormatLine "Backup file" $BackupFile ] . "\n" . \ - [ $FormatLine "Export file" $ExportFile ] . "\n" . \ - [ $FormatLine "Config file" $ConfigFile ]); \ - attach=$Attach; remove-attach=true }); - - # wait for the mail to be sent - :local I 0; - :while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={ - :if ($I >= 120) do={ - $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - :delay 1s; - :set I ($I + 1); - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/backup-partition.rsc b/backup-partition.rsc deleted file mode 100644 index 1f0cf2e..0000000 --- a/backup-partition.rsc +++ /dev/null @@ -1,126 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-partition -# Copyright (c) 2022-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: backup-script, order=70 -# requires RouterOS, version=7.15 -# requires device-mode, scheduler -# -# save configuration to fallback partition -# https://rsc.eworm.de/doc/backup-partition.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global BackupPartitionCopyBeforeFeatureUpdate; - :global PackagesUpdateBackupFailure; - - :global LogPrint; - :global ScriptFromTerminal; - :global ScriptLock; - :global VersionToNum; - - :local CopyTo do={ - :local ScriptName [ :tostr $1 ]; - :local FallbackTo [ :toid $2 ]; - :local FallbackToName [ :tostr $3 ]; - - :global LogPrint; - - :do { - /partitions/copy-to $FallbackTo; - $LogPrint info $ScriptName ("Copied RouterOS to partition '" . $FallbackToName . "'."); - :return true; - } on-error={ - $LogPrint error $ScriptName ("Failed copying RouterOS to partition '" . $FallbackToName . "'!"); - :return false; - } - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrint error $ScriptName ("Device does not have a fallback partition."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :local ActiveRunning [ /partitions/find where active running ]; - - :if ([ :len $ActiveRunning ] < 1) do={ - $LogPrint error $ScriptName ("Device is not running from active partition."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :local FallbackToName [ /partitions/get $ActiveRunning fallback-to ]; - :local FallbackTo [ /partition/find where name=$FallbackToName !active ]; - - :if ([ :len $FallbackTo ] < 1) do={ - $LogPrint error $ScriptName ("There is no inactive partition named '" . $FallbackToName . "'."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ /partitions/get $ActiveRunning version ] != [ /partitions/get $FallbackTo version]) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put ("The partitions have different RouterOS versions. Copy over to '" . $FallbackToName . "'? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - } - } else={ - :local Update [ /system/package/update/get ]; - :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; - :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - :local BitMask [ $VersionToNum "255.255zero0" ]; - :if ($BackupPartitionCopyBeforeFeatureUpdate = true && $NumLatest > 0 && \ - ($NumInstalled & $BitMask) != ($NumLatest & $BitMask)) do={ - :if ([ $CopyTo $ScriptName $FallbackTo $FallbackToName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - } - } - } - - :do { - /system/scheduler/add start-time=startup name="running-from-backup-partition" \ - on-event=(":log warning (\"Running from partition '\" . " . \ - "[ /partitions/get [ find where running ] name ] . \"'!\")"); - /partitions/save-config-to $FallbackTo; - /system/scheduler/remove "running-from-backup-partition"; - $LogPrint info $ScriptName ("Saved configuration to partition '" . $FallbackToName . "'."); - } on-error={ - /system/scheduler/remove [ find where name="running-from-backup-partition" ]; - $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackToName . "'!"); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/backup-upload.rsc b/backup-upload.rsc deleted file mode 100644 index 14c3914..0000000 --- a/backup-upload.rsc +++ /dev/null @@ -1,178 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-upload -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: backup-script, order=50 -# requires RouterOS, version=7.15 -# requires device-mode, fetch -# -# create and upload backup and config file -# https://rsc.eworm.de/doc/backup-upload.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global BackupPassword; - :global BackupRandomDelay; - :global BackupSendBinary; - :global BackupSendExport; - :global BackupSendGlobalConfig; - :global BackupUploadPass; - :global BackupUploadUrl; - :global BackupUploadUser; - :global Domain; - :global Identity; - :global PackagesUpdateBackupFailure; - - :global CleanName; - :global DeviceInfo; - :global IfThenElse; - :global LogPrint; - :global MkDir; - :global RandomDelay; - :global RmDir; - :global RmFile; - :global ScriptFromTerminal; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global WaitForFile; - :global WaitFullyConnected; - - :if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); - :set ExitOK true; - :error false; - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; - } - - # filename based on identity - :local DirName ("tmpfs/" . $ScriptName); - :local FileName [ $CleanName ($Identity . "." . $Domain) ]; - :local FilePath ($DirName . "/" . $FileName); - :local BackupFile "none"; - :local ExportFile "none"; - :local ConfigFile "none"; - :local Failed 0; - - :if ([ $MkDir $DirName ] = false) do={ - $LogPrint error $ScriptName ("Failed creating directory!"); - :set ExitOK true; - :error false; - } - - # binary backup - :if ($BackupSendBinary = true) do={ - /system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword; - $WaitForFile ($FilePath . ".backup"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); - :set BackupFile [ /file/get ($FilePath . ".backup") ]; - :set ($BackupFile->"name") ($FileName . ".backup"); - } on-error={ - $LogPrint error $ScriptName ("Uploading backup file failed!"); - :set BackupFile "failed"; - :set Failed 1; - } - - $RmFile ($FilePath . ".backup"); - } - - # create configuration export - :if ($BackupSendExport = true) do={ - /export terse show-sensitive file=$FilePath; - $WaitForFile ($FilePath . ".rsc"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); - :set ExportFile [ /file/get ($FilePath . ".rsc") ]; - :set ($ExportFile->"name") ($FileName . ".rsc"); - } on-error={ - $LogPrint error $ScriptName ("Uploading configuration export failed!"); - :set ExportFile "failed"; - :set Failed 1; - } - - $RmFile ($FilePath . ".rsc"); - } - - # global-config-overlay - :if ($BackupSendGlobalConfig = true) do={ - # Do *NOT* use '/file/add ...' here, as it is limited to 4095 bytes! - :execute script={ :put [ /system/script/get global-config-overlay source ]; } \ - file=($FilePath . ".conf\00"); - $WaitForFile ($FilePath . ".conf"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".conf") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".conf"); - :set ConfigFile [ /file/get ($FilePath . ".conf") ]; - :set ($ConfigFile->"name") ($FileName . ".conf"); - } on-error={ - $LogPrint error $ScriptName ("Uploading global-config-overlay failed!"); - :set ConfigFile "failed"; - :set Failed 1; - } - - $RmFile ($FilePath . ".conf"); - } - - :local FileInfo do={ - :local Name $1; - :local File $2; - - :global FormatLine; - :global HumanReadableNum; - :global IfThenElse; - - :return \ - [ $IfThenElse ([ :typeof $File ] = "array") \ - ($Name . ":\n" . [ $FormatLine " name" ($File->"name") ] . "\n" . \ - [ $FormatLine " size" ([ $HumanReadableNum ($File->"size") 1024 ] . "B") ]) \ - [ $FormatLine $Name $File ] ]; - } - - $SendNotification2 ({ origin=$ScriptName; \ - subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk,arrow-up" ] . "Backup & Config upload") ]; \ - message=("Backup and config export upload for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - [ $FileInfo "Backup file" $BackupFile ] . "\n" . \ - [ $FileInfo "Export file" $ExportFile ] . "\n" . \ - [ $FileInfo "Config file" $ConfigFile ]); silent=true }); - - :if ($Failed = 1) do={ - :set PackagesUpdateBackupFailure true; - } - $RmDir $DirName; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/bridge-port-to-default b/bridge-port-to-default new file mode 100644 index 0000000..286fb45 --- /dev/null +++ b/bridge-port-to-default @@ -0,0 +1,49 @@ +#!rsc by RouterOS +# RouterOS script: bridge-port-to-default +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# reset bridge ports to default bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md + +:global BridgePortTo; + +:global IfThenElse; +:global LogPrintExit; +:global ParseKeyValueStore; + +:foreach BridgePort in=[ / interface bridge port find where !(comment=[]) ] do={ + :local BridgePortVal [ / interface bridge port get $BridgePort ]; + :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ + :if ($Config = $BridgePortTo) do={ + :local DHCPClient [ / ip dhcp-client find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; + + :if ($BridgeDefault = "dhcp-client") do={ + :if ([ :len $DHCPClient ] != 1) do={ + $LogPrintExit warning ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ + " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + } + :local DHCPClientDisabled [ / ip dhcp-client get $DHCPClient disabled ]; + + :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ + $LogPrintExit info ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + / interface bridge port disable $BridgePort; + / ip dhcp-client enable $DHCPClient; + } + } else={ + :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ + $LogPrintExit info ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + :if ([ :len $DHCPClient ] = 1) do={ + / ip dhcp-client disable $DHCPClient; + :delay 200ms; + } + / interface bridge port set disabled=no bridge=$BridgeDefault $BridgePort; + } else={ + $LogPrintExit debug ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . ".") false; + } + } + } + } +} diff --git a/bridge-port-toggle b/bridge-port-toggle new file mode 100644 index 0000000..78a64f7 --- /dev/null +++ b/bridge-port-toggle @@ -0,0 +1,17 @@ +#!rsc by RouterOS +# RouterOS script: bridge-port-toggle +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# toggle bridge ports between default and alt bridge +# https://git.eworm.de/cgit/routeros-scripts/about/doc/bridge-port.md + +:global BridgePortTo; + +:if ($BridgePortTo != "default") do={ + :set BridgePortTo "default"; +} else={ + :set BridgePortTo "alt"; +} + +/ system script run bridge-port-to-default; diff --git a/capsman-download-packages b/capsman-download-packages new file mode 100644 index 0000000..b6bff3a --- /dev/null +++ b/capsman-download-packages @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages +# Copyright (c) 2018-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md + +:global CleanFilePath; +:global DownloadPackage; +:global LogPrintExit; +:global MkDir; +:global ScriptLock; +:global WaitFullyConnected; + +$ScriptLock "capsman-download-packages"; +$WaitFullyConnected; + +:local PackagePath [ $CleanFilePath [ / caps-man manager get package-path ] ]; +:local InstalledVersion [ / system package update get installed-version ]; +:local Updated false; + +:if ([ :len [ / file find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $MkDir $PackagePath ] = false) do={ + $LogPrintExit warning ("Creating directory at package path (" . \ + $PackagePath . ") failed!") true; + } + $LogPrintExit info ("Created directory at package path (" . $PackagePath . \ + "). Please place your packages!") false; +} + +:foreach Package in=[ / file find where type=package \ + package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :local File [ / file get $Package ]; + :if ($File->"package-architecture" = "mips") do={ + :set ($File->"package-architecture") "mipsbe"; + } + :if ($File->"package-name" = "wireless@") do={ + :set ($File->"package-name") "wireless"; + } + :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion ($File->"package-architecture") $PackagePath ] = true) do={ + :set Updated true; + / file remove $Package; + } +} + +:if ($Updated = true) do={ + :if ([ :len [ / system script find where name="capsman-rolling-upgrade" ] ] > 0) do={ + / system script run capsman-rolling-upgrade; + } else={ + / caps-man remote-cap upgrade [ find where version!=$InstalledVersion ]; + } +} diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc deleted file mode 100644 index 25c43f5..0000000 --- a/capsman-download-packages.capsman.rsc +++ /dev/null @@ -1,92 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-download-packages.capsman -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# download and cleanup packages for CAP installation from CAPsMAN -# https://rsc.eworm.de/doc/capsman-download-packages.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CleanFilePath; - :global DownloadPackage; - :global LogPrint; - :global MkDir; - :global RmFile; - :global ScriptLock; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; - :local InstalledVersion [ /system/package/update/get installed-version ]; - :local Updated false; - - :if ([ :len $PackagePath ] = 0) do={ - $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); - :set ExitOK true; - :error false; - } - - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!"); - :set ExitOK true; - :error false; - } - $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!"); - } - - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - $RmFile ($File->"name"); - } - } - - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrint info $ScriptName ("No packages available, downloading default set."); - :foreach Arch in={ "arm"; "mipsbe" } do={ - :foreach Package in={ "routeros"; "wireless" } do={ - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } - } - } - } - - :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.capsman\r?\n" ]; - :if ([ :len $Scripts ] > 0) do={ - :foreach Script in=$Scripts do={ - /system/script/run $Script; - } - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc deleted file mode 100644 index b269838..0000000 --- a/capsman-download-packages.template.rsc +++ /dev/null @@ -1,103 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-download-packages%TEMPL% -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# download and cleanup packages for CAP installation from CAPsMAN -# https://rsc.eworm.de/doc/capsman-download-packages.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CleanFilePath; - :global DownloadPackage; - :global LogPrint; - :global MkDir; - :global RmFile; - :global ScriptLock; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; - :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; - :local InstalledVersion [ /system/package/update/get installed-version ]; - :local Updated false; - - :if ([ :len $PackagePath ] = 0) do={ - $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); - :set ExitOK true; - :error false; - } - - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!"); - :set ExitOK true; - :error false; - } - $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!"); - } - - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - $RmFile ($File->"name"); - } - } - - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrint info $ScriptName ("No packages available, downloading default set."); -# NOT /interface/wifi/ # - :foreach Arch in={ "arm"; "mipsbe" } do={ - :foreach Package in={ "routeros"; "wireless" } do={ -# NOT /interface/wifi/ # -# NOT /caps-man/ # - :foreach Arch in={ "arm"; "arm64" } do={ - :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; - "arm64"={ "routeros"; "wifi-qcom" } }; - :foreach Package in=($Packages->$Arch) do={ -# NOT /caps-man/ # - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } - } - } - } - - :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade%TEMPL%\r?\n" ]; - :if ([ :len $Scripts ] > 0) do={ - :foreach Script in=$Scripts do={ - /system/script/run $Script; - } - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc deleted file mode 100644 index 901bb0a..0000000 --- a/capsman-download-packages.wifi.rsc +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-download-packages.wifi -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# download and cleanup packages for CAP installation from CAPsMAN -# https://rsc.eworm.de/doc/capsman-download-packages.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CleanFilePath; - :global DownloadPackage; - :global LogPrint; - :global MkDir; - :global RmFile; - :global ScriptLock; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; - :local InstalledVersion [ /system/package/update/get installed-version ]; - :local Updated false; - - :if ([ :len $PackagePath ] = 0) do={ - $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages."); - :set ExitOK true; - :error false; - } - - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!"); - :set ExitOK true; - :error false; - } - $LogPrint info $ScriptName ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!"); - } - - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - $RmFile ($File->"name"); - } - } - - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ - $LogPrint info $ScriptName ("No packages available, downloading default set."); - :foreach Arch in={ "arm"; "arm64" } do={ - :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; - "arm64"={ "routeros"; "wifi-qcom" } }; - :foreach Package in=($Packages->$Arch) do={ - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } - } - } - } - - :if ($Updated = true) do={ - :local Scripts [ /system/script/find where source~"\n# provides: capsman-rolling-upgrade.wifi\r?\n" ]; - :if ([ :len $Scripts ] > 0) do={ - :foreach Script in=$Scripts do={ - /system/script/run $Script; - } - } else={ - /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade new file mode 100644 index 0000000..1f091b8 --- /dev/null +++ b/capsman-rolling-upgrade @@ -0,0 +1,28 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade +# Copyright (c) 2018-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md + +:global LogPrintExit; +:global ScriptLock; + +$ScriptLock "capsman-rolling-upgrade"; + +:local InstalledVersion [ / system package update get installed-version ]; + +:local RemoteCapCount [ :len [ / caps-man remote-cap find ] ]; +:if ($RemoteCapCount > 0) do={ + :local Delay (600 / $RemoteCapCount); + :if ($Delay > 120) do={ :set Delay 120; } + :foreach RemoteCap in=[ / caps-man remote-cap find where version!=$InstalledVersion ] do={ + :local RemoteCapVal [ / caps-man remote-cap get $RemoteCap ]; + $LogPrintExit info ("Starting upgrade for " . $RemoteCapVal->"name" . \ + " (" . $RemoteCapVal->"identity" . ")...") false; + / caps-man remote-cap upgrade [ find where name=$RemoteCapVal->"name" ]; + :delay ($Delay . "s"); + } +} diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc deleted file mode 100644 index 791b3db..0000000 --- a/capsman-rolling-upgrade.capsman.rsc +++ /dev/null @@ -1,50 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade.capsman -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# provides: capsman-rolling-upgrade.capsman -# requires RouterOS, version=7.15 -# -# upgrade CAPs one after another -# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local InstalledVersion [ /system/package/update/get installed-version ]; - - :local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; - :if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ - $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")..."); - /caps-man/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); - } - :delay ($Delay . "s"); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc deleted file mode 100644 index 0b1cc2b..0000000 --- a/capsman-rolling-upgrade.template.rsc +++ /dev/null @@ -1,58 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade%TEMPL% -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# provides: capsman-rolling-upgrade%TEMPL% -# requires RouterOS, version=7.15 -# -# upgrade CAPs one after another -# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local InstalledVersion [ /system/package/update/get installed-version ]; - - :local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; - :local RemoteCapCount [ :len [ /interface/wifi/capsman/remote-cap/find ] ]; - :if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ - :foreach RemoteCap in=[ /interface/wifi/capsman/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; - :local RemoteCapVal [ /interface/wifi/capsman/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ -# NOT /caps-man/ # - :set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name"); -# NOT /caps-man/ # - $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")..."); - /caps-man/remote-cap/upgrade $RemoteCap; - /interface/wifi/capsman/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); - } - :delay ($Delay . "s"); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc deleted file mode 100644 index 4afdee2..0000000 --- a/capsman-rolling-upgrade.wifi.rsc +++ /dev/null @@ -1,51 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade.wifi -# Copyright (c) 2018-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# provides: capsman-rolling-upgrade.wifi -# requires RouterOS, version=7.15 -# -# upgrade CAPs one after another -# https://rsc.eworm.de/doc/capsman-rolling-upgrade.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local InstalledVersion [ /system/package/update/get installed-version ]; - - :local RemoteCapCount [ :len [ /interface/wifi/capsman/remote-cap/find ] ]; - :if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /interface/wifi/capsman/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /interface/wifi/capsman/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ - :set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name"); - $LogPrint info $ScriptName ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")..."); - /interface/wifi/capsman/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrint warning $ScriptName ("Remote CAP vanished, skipping upgrade."); - } - :delay ($Delay . "s"); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/certificate-renew-issued b/certificate-renew-issued new file mode 100644 index 0000000..2eeaba0 --- /dev/null +++ b/certificate-renew-issued @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: certificate-renew-issued +# Copyright (c) 2019-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# renew locally issued certificates +# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md + +:global CertIssuedExportPass; + +:global LogPrintExit; +:global MkDir; + +:foreach Cert in=[ / certificate find where issued expires-after<3w ] do={ + :local CertVal [ / certificate get $Cert ]; + / certificate issued-revoke $Cert; + / certificate set name=($CertVal->"name" . "-revoked-" . [ / system clock get date ]) $Cert; + / certificate add name=($CertVal->"name") common-name=($CertVal->"common-name") \ + key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); + / certificate sign ($CertVal->"name") ca=($CertVal->"ca"); + :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ + :if ([ $MkDir "cert-issued" ] = true) do={ + / certificate export-certificate ($CertVal->"name") type=pkcs12 \ + file-name=("cert-issued/" . $CertVal->"common-name") \ + export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); + $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . \ + "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; + } else={ + $LogPrintExit warning ("Failed creating directory, not exporting certificate.") false; + } + } else={ + $LogPrintExit info ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; + } +} diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc deleted file mode 100644 index 91a48de..0000000 --- a/certificate-renew-issued.rsc +++ /dev/null @@ -1,52 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# renew locally issued certificates -# https://rsc.eworm.de/doc/certificate-renew-issued.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CertIssuedExportPass; - - :global LogPrint; - :global MkDir; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ - :local CertVal [ /certificate/get $Cert ]; - /certificate/issued-revoke $Cert; - /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; - /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ - key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); - /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); - :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ - :if ([ $MkDir "cert-issued" ] = true) do={ - /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ - file-name=("cert-issued/" . $CertVal->"common-name") \ - export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . \ - "', exported to 'cert-issued/" . $CertVal->"common-name" . ".p12'."); - } else={ - $LogPrint warning $ScriptName ("Failed creating directory, not exporting certificate."); - } - } else={ - $LogPrint info $ScriptName ("Issued a new certificate for '" . $CertVal->"common-name" . "'."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/certs/Certum-Trusted-Network-CA.pem b/certs/Certum-Trusted-Network-CA.pem deleted file mode 100644 index a48e706..0000000 --- a/certs/Certum-Trusted-Network-CA.pem +++ /dev/null @@ -1,29 +0,0 @@ -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- diff --git a/certs/DigiCert ECC Secure Server CA.pem b/certs/DigiCert ECC Secure Server CA.pem new file mode 100644 index 0000000..3eca7fc --- /dev/null +++ b/certs/DigiCert ECC Secure Server CA.pem @@ -0,0 +1,166 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:cb:28:ba:46:5e:e5:39:08:76:74:70:f3:cd:c6:12 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Mar 8 12:00:00 2013 GMT + Not After : Mar 8 12:00:00 2023 GMT + Subject: C = US, O = DigiCert Inc, CN = DigiCert ECC Secure Server CA + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:e2:08:42:ea:77:d8:24:de:a0:2c:64:a4:13:ce: + 40:9c:23:72:a9:02:0a:0e:37:3f:21:36:b8:8d:53: + 14:f6:d5:91:95:4b:f3:96:02:8d:71:1e:c4:d8:cb: + a7:9f:5e:ef:a0:e6:7f:5a:92:11:96:53:6f:eb:c0: + cb:3f:ae:fd:5b:3f:47:24:e7:9a:07:2e:96:be:a8: + 2f:bb:57:18:af:71:a4:bd:78:3a:1e:e8:5b:3c:6b: + 64:11:2b:cc:34:2b:8c + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + A3:9D:E6:1F:F9:DA:39:4F:C0:6E:E8:91:CB:95:A5:DA:31:E2:0A:9F + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha384WithRSAEncryption + c7:8a:a0:43:4b:ec:74:c9:c5:ab:d5:1f:30:35:36:6e:98:56: + 7b:48:ac:05:63:ae:7b:9a:57:24:57:cc:6f:fa:de:ab:6d:9c: + c7:b6:ba:ec:ce:e7:ca:73:64:db:df:04:37:0a:00:49:b3:3f: + 9f:26:ad:91:8c:20:e8:1f:88:0e:2a:fb:66:37:c8:30:e8:d2: + c2:24:a7:45:48:2d:ea:01:50:4a:31:94:13:df:8d:5f:da:2a: + bb:49:3c:61:f3:79:c8:9c:66:92:1a:96:2a:f4:7b:36:58:a3: + 2c:41:10:74:1a:d3:ed:48:b6:d2:bb:8a:06:45:71:33:10:30: + 7a:7a:98:21:dd:24:b9:ec:9c:b5:92:07:ad:83:c6:c4:6a:f8: + 77:e6:35:be:13:0f:27:64:b2:43:bf:83:e9:77:56:db:08:87: + 94:47:14:f5:5f:28:af:a3:68:4c:83:8f:60:f7:96:80:79:85: + 6a:76:26:9d:95:0c:20:03:8d:3e:ee:7a:28:65:64:66:a4:d9: + 83:ea:99:74:cd:6e:4d:7d:1c:eb:8d:b2:c5:af:16:1b:4e:c8: + f3:55:ea:88:38:11:34:1d:11:af:3f:07:a8:4f:6a:d2:74:11: + 2f:2a:fc:73:b7:5f:c2:15:43:05:6c:d6:7d:da:02:bd:22:9b: + 4f:d3:f9:77 +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIQCssoukZe5TkIdnRw883GEjANBgkqhkiG9w0BAQwFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEwxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJjAkBgNVBAMTHURpZ2lDZXJ0IEVDQyBT +ZWN1cmUgU2VydmVyIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ghC6nfYJN6g +LGSkE85AnCNyqQIKDjc/ITa4jVMU9tWRlUvzlgKNcR7E2Munn17voOZ/WpIRllNv +68DLP679Wz9HJOeaBy6Wvqgvu1cYr3GkvXg6HuhbPGtkESvMNCuMo4IBITCCAR0w +EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwNAYIKwYBBQUHAQEE +KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQgYDVR0f +BDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xv +YmFsUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc +aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUo53mH/naOU/A +buiRy5Wl2jHiCp8wHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ +KoZIhvcNAQEMBQADggEBAMeKoENL7HTJxavVHzA1Nm6YVntIrAVjrnuaVyRXzG/6 +3qttnMe2uuzO58pzZNvfBDcKAEmzP58mrZGMIOgfiA4q+2Y3yDDo0sIkp0VILeoB +UEoxlBPfjV/aKrtJPGHzecicZpIalir0ezZYoyxBEHQa0+1IttK7igZFcTMQMHp6 +mCHdJLnsnLWSB62DxsRq+HfmNb4TDydkskO/g+l3VtsIh5RHFPVfKK+jaEyDj2D3 +loB5hWp2Jp2VDCADjT7ueihlZGak2YPqmXTNbk19HOuNssWvFhtOyPNV6og4ETQd +Ea8/B6hPatJ0ES8q/HO3X8IVQwVs1n3aAr0im0/T+Xc= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: + 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: + cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: + e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: + df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: + 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: + 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: + 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: + c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: + a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: + 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: + a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: + 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: + 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: + d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: + 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: + f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: + af:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha1WithRSAEncryption + cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: + 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: + f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: + a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: + 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: + 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: + ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: + 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: + e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: + cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: + 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: + 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: + 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: + f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: + 95:95:6d:de +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/certs/DigiCert-Global-Root-G2.pem b/certs/DigiCert-Global-Root-G2.pem deleted file mode 100644 index 8af6c7a..0000000 --- a/certs/DigiCert-Global-Root-G2.pem +++ /dev/null @@ -1,29 +0,0 @@ -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- diff --git a/certs/DigiCert-Global-Root-G3.pem b/certs/DigiCert-Global-Root-G3.pem deleted file mode 100644 index 12324dc..0000000 --- a/certs/DigiCert-Global-Root-G3.pem +++ /dev/null @@ -1,22 +0,0 @@ -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- diff --git a/certs/E1.pem b/certs/E1.pem new file mode 100644 index 0000000..4c3c212 --- /dev/null +++ b/certs/E1.pem @@ -0,0 +1,243 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b3:bd:df:f8:a7:84:5b:bc:e9:03:a0:41:35:b3:4a:45 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 15 16:00:00 2025 GMT + Subject: C = US, O = Let's Encrypt, CN = E1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:24:5c:2d:a2:2a:fd:1c:4b:a6:5d:97:73:27:31: + ac:b2:a0:69:62:ef:65:e8:a6:b0:f0:ac:4b:9f:ff: + 1c:0b:70:0f:d3:98:2f:4d:fc:0f:00:9b:37:f0:74: + 05:57:32:97:2e:05:ef:2a:43:25:a3:fb:6e:34:27: + 13:f6:4f:7e:69:d3:02:99:5e:eb:24:47:92:c1:24: + 9b:e6:b1:21:8f:c1:24:81:fc:68:cc:1f:69:ba:58: + f5:19:22:f7:74:c6:16 + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 5A:F3:ED:2B:FC:36:C2:37:79:B9:52:30:EA:54:6F:CF:55:CB:2E:AC + X509v3 Authority Key Identifier: + keyid:7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + + Authority Information Access: + CA Issuers - URI:http://x2.i.lencr.org/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://x2.c.lencr.org/ + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:7b:74:d5:52:13:8d:61:fe:0d:ba:3f:03:00:9d: + f3:d7:98:84:d9:57:2e:bd:e9:0f:9c:5c:48:04:21:f2:cb:b3: + 60:72:8e:97:d6:12:4f:ca:44:f6:42:c9:d3:7b:86:a9:02:30: + 5a:b1:b1:b4:ed:ea:60:99:20:b1:38:03:ca:3d:a0:26:b8:ee: + 6e:2d:4a:f6:c6:66:1f:33:9a:db:92:4a:d5:f5:29:13:c6:70: + 62:28:ba:23:8c:cf:3d:2f:cb:82:e9:7f +-----BEGIN CERTIFICATE----- +MIICxjCCAk2gAwIBAgIRALO93/inhFu86QOgQTWzSkUwCgYIKoZIzj0EAwMwTzEL +MAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNo +IEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDIwHhcNMjAwOTA0MDAwMDAwWhcN +MjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5j +cnlwdDELMAkGA1UEAxMCRTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQkXC2iKv0c +S6Zdl3MnMayyoGli72XoprDwrEuf/xwLcA/TmC9N/A8AmzfwdAVXMpcuBe8qQyWj ++240JxP2T35p0wKZXuskR5LBJJvmsSGPwSSB/GjMH2m6WPUZIvd0xhajggEIMIIB +BDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFFrz7Sv8NsI3eblSMOpUb89V +yy6sMB8GA1UdIwQYMBaAFHxClq7eS0g7+pL4nozPbYupcjeVMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gyLmkubGVuY3Iub3JnLzAnBgNVHR8E +IDAeMBygGqAYhhZodHRwOi8veDIuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYG +Z4EMAQIBMA0GCysGAQQBgt8TAQEBMAoGCCqGSM49BAMDA2cAMGQCMHt01VITjWH+ +Dbo/AwCd89eYhNlXLr3pD5xcSAQh8suzYHKOl9YST8pE9kLJ03uGqQIwWrGxtO3q +YJkgsTgDyj2gJrjubi1K9sZmHzOa25JK1fUpE8ZwYii6I4zPPS/Lgul/ +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:d2:9d:d1:72:ea:ee:a7:80:c1:2c:6c:e9:2f:87:52 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 17 16:00:00 2040 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:cd:9b:d5:9f:80:83:0a:ec:09:4a:f3:16:4a:3e: + 5c:cf:77:ac:de:67:05:0d:1d:07:b6:dc:16:fb:5a: + 8b:14:db:e2:71:60:c4:ba:45:95:11:89:8e:ea:06: + df:f7:2a:16:1c:a4:b9:c5:c5:32:e0:03:e0:1e:82: + 18:38:8b:d7:45:d8:0a:6a:6e:e6:00:77:fb:02:51: + 7d:22:d8:0a:6e:9a:5b:77:df:f0:fa:41:ec:39:dc: + 75:ca:68:07:0c:1f:ea + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 7C:42:96:AE:DE:4B:48:3B:FA:92:F8:9E:8C:CF:6D:8B:A9:72:37:95 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:7b:79:4e:46:50:84:c2:44:87:46:1b:45:70:ff: + 58:99:de:f4:fd:a4:d2:55:a6:20:2d:74:d6:34:bc:41:a3:50: + 5f:01:27:56:b4:be:27:75:06:af:12:2e:75:98:8d:fc:02:31: + 00:8b:f5:77:6c:d4:c8:65:aa:e0:0b:2c:ee:14:9d:27:37:a4: + f9:53:a5:51:e4:29:83:d7:f8:90:31:5b:42:9f:0a:f5:fe:ae: + 00:68:e7:8c:49:0f:b6:6f:5b:5b:15:f2:e7 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/certs/GTS CA 1O1.pem b/certs/GTS CA 1O1.pem new file mode 100644 index 0000000..ccdba4d --- /dev/null +++ b/certs/GTS CA 1O1.pem @@ -0,0 +1,186 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 01:e3:b4:9a:a1:8d:8a:a9:81:25:69:50:b8 + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Jun 15 00:00:42 2017 GMT + Not After : Dec 15 00:00:42 2021 GMT + Subject: C = US, O = Google Trust Services, CN = GTS CA 1O1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d0:18:cf:45:d4:8b:cd:d3:9c:e4:40:ef:7e:b4: + dd:69:21:1b:c9:cf:3c:8e:4c:75:b9:0f:31:19:84: + 3d:9e:3c:29:ef:50:0d:10:93:6f:05:80:80:9f:2a: + a0:bd:12:4b:02:e1:3d:9f:58:16:24:fe:30:9f:0b: + 74:77:55:93:1d:4b:f7:4d:e1:92:82:10:f6:51:ac: + 0c:c3:b2:22:94:0f:34:6b:98:10:49:e7:0b:9d:83: + 39:dd:20:c6:1c:2d:ef:d1:18:61:65:e7:23:83:20: + a8:23:12:ff:d2:24:7f:d4:2f:e7:44:6a:5b:4d:d7: + 50:66:b0:af:9e:42:63:05:fb:e0:1c:c4:63:61:af: + 9f:6a:33:ff:62:97:bd:48:d9:d3:7c:14:67:dc:75: + dc:2e:69:e8:f8:6d:78:69:d0:b7:10:05:b8:f1:31: + c2:3b:24:fd:1a:33:74:f8:23:e0:ec:6b:19:8a:16: + c6:e3:cd:a4:cd:0b:db:b3:a4:59:60:38:88:3b:ad: + 1d:b9:c6:8c:a7:53:1b:fc:bc:d9:a4:ab:bc:dd:3c: + 61:d7:93:15:98:ee:81:bd:8f:e2:64:47:20:40:06: + 4e:d7:ac:97:e8:b9:c0:59:12:a1:49:25:23:e4:ed: + 70:34:2c:a5:b4:63:7c:f9:a3:3d:83:d1:cd:6d:24: + ac:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B + X509v3 Authority Key Identifier: + keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + + Authority Information Access: + OCSP - URI:http://ocsp.pki.goog/gsr2 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.pki.goog/gsr2/gsr2.crl + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.2 + CPS: https://pki.goog/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 1a:80:3e:36:79:fb:f3:2e:a9:46:37:7d:5e:54:16:35:ae:c7: + 4e:08:99:fe:bd:d1:34:69:26:52:66:07:3d:0a:ba:49:cb:62: + f4:f1:1a:8e:fc:11:4f:68:96:4c:74:2b:d3:67:de:b2:a3:aa: + 05:8d:84:4d:4c:20:65:0f:a5:96:da:0d:16:f8:6c:3b:db:6f: + 04:23:88:6b:3a:6c:c1:60:bd:68:9f:71:8e:ee:2d:58:34:07: + f0:d5:54:e9:86:59:fd:7b:5e:0d:21:94:f5:8c:c9:a8:f8:d8: + f2:ad:cc:0f:1a:f3:9a:a7:a9:04:27:f9:a3:c9:b0:ff:02:78: + 6b:61:ba:c7:35:2b:e8:56:fa:4f:c3:1c:0c:ed:b6:3c:b4:4b: + ea:ed:cc:e1:3c:ec:dc:0d:8c:d6:3e:9b:ca:42:58:8b:cc:16: + 21:17:40:bc:a2:d6:66:ef:da:c4:15:5b:cd:89:aa:9b:09:26: + e7:32:d2:0d:6e:67:20:02:5b:10:b0:90:09:9c:0c:1f:9e:ad: + d8:3b:ea:a1:fc:6c:e8:10:5c:08:52:19:51:2a:71:bb:ac:7a: + b5:dd:15:ed:2b:c9:08:2a:2c:8a:b4:a6:21:ab:63:ff:d7:52: + 49:50:d0:89:b7:ad:f2:af:fb:50:ae:2f:e1:95:0d:f3:46:ad: + 9d:9c:f5:ca +-----BEGIN CERTIFICATE----- +MIIESjCCAzKgAwIBAgINAeO0mqGNiqmBJWlQuDANBgkqhkiG9w0BAQsFADBMMSAw +HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs +U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy +MTUwMDAwNDJaMEIxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg +U2VydmljZXMxEzARBgNVBAMTCkdUUyBDQSAxTzEwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDQGM9F1IvN05zkQO9+tN1pIRvJzzyOTHW5DzEZhD2ePCnv +UA0Qk28FgICfKqC9EksC4T2fWBYk/jCfC3R3VZMdS/dN4ZKCEPZRrAzDsiKUDzRr +mBBJ5wudgzndIMYcLe/RGGFl5yODIKgjEv/SJH/UL+dEaltN11BmsK+eQmMF++Ac +xGNhr59qM/9il71I2dN8FGfcddwuaej4bXhp0LcQBbjxMcI7JP0aM3T4I+DsaxmK +FsbjzaTNC9uzpFlgOIg7rR25xoynUxv8vNmkq7zdPGHXkxWY7oG9j+JkRyBABk7X +rJfoucBZEqFJJSPk7XA0LKW0Y3z5oz2D0c1tJKwHAgMBAAGjggEzMIIBLzAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1Ud +EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJjR+G4Q68+b7GCfGJAboOt9Cf0rMB8G +A1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYuMDUGCCsGAQUFBwEBBCkwJzAl +BggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzAp +MCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0g +BDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9y +ZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAGoA+Nnn78y6pRjd9XlQWNa7H +TgiZ/r3RNGkmUmYHPQq6Scti9PEajvwRT2iWTHQr02fesqOqBY2ETUwgZQ+lltoN +FvhsO9tvBCOIazpswWC9aJ9xju4tWDQH8NVU6YZZ/XteDSGU9YzJqPjY8q3MDxrz +mqepBCf5o8mw/wJ4a2G6xzUr6Fb6T8McDO22PLRL6u3M4Tzs3A2M1j6bykJYi8wW +IRdAvKLWZu/axBVbzYmqmwkm5zLSDW5nIAJbELCQCZwMH56t2Dvqofxs6BBcCFIZ +USpxu6x6td0V7SvJCCosirSmIatj/9dSSVDQibet8q/7UK4v4ZUN80atnZz1yg== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:0f:86:26:e6:0d + Signature Algorithm: sha1WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Dec 15 08:00:00 2006 GMT + Not After : Dec 15 08:00:00 2021 GMT + Subject: OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e: + 21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f: + c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8: + 60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac: + 52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc: + 7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a: + 07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5: + b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f: + 5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84: + 6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21: + ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb: + 24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b: + 73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b: + 4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88: + 5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa: + 09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01: + c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2: + 9b:8f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root-r2.crl + + X509v3 Authority Key Identifier: + keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + + Signature Algorithm: sha1WithRSAEncryption + 99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac: + 27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b: + 4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08: + 93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1: + 54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba: + 29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43: + 2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d: + 8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39: + 87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d: + 01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff: + ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0: + 41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9: + 8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20: + 78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e: + 81:e1:93:2e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- diff --git a/certs/GTS-Root-R1.pem b/certs/GTS-Root-R1.pem deleted file mode 100644 index a6095d2..0000000 --- a/certs/GTS-Root-R1.pem +++ /dev/null @@ -1,38 +0,0 @@ -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 159662320309726417404178440727 -# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 -# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a -# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf ------BEGIN CERTIFICATE----- -MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo -27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w -Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw -TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl -qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH -szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 -Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk -MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 -wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p -aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN -VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID -AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb -C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe -QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy -h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 -7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J -ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef -MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ -Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT -6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ -0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm -2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb -bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c ------END CERTIFICATE----- diff --git a/certs/GTS-Root-R4.pem b/certs/GTS-Root-R4.pem deleted file mode 100644 index 16a1c36..0000000 --- a/certs/GTS-Root-R4.pem +++ /dev/null @@ -1,20 +0,0 @@ -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 159662532700760215368942768210 -# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 -# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 -# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d ------BEGIN CERTIFICATE----- -MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD -VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG -A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw -WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz -IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi -AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi -QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR -HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D -9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 -p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD ------END CERTIFICATE----- diff --git a/certs/Go Daddy Secure Certificate Authority - G2.pem b/certs/Go Daddy Secure Certificate Authority - G2.pem new file mode 100644 index 0000000..4faba90 --- /dev/null +++ b/certs/Go Daddy Secure Certificate Authority - G2.pem @@ -0,0 +1,178 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b9:e0:cb:10:d4:af:76:bd:d4:93:62:eb:30:64: + b8:81:08:6c:c3:04:d9:62:17:8e:2f:ff:3e:65:cf: + 8f:ce:62:e6:3c:52:1c:da:16:45:4b:55:ab:78:6b: + 63:83:62:90:ce:0f:69:6c:99:c8:1a:14:8b:4c:cc: + 45:33:ea:88:dc:9e:a3:af:2b:fe:80:61:9d:79:57: + c4:cf:2e:f4:3f:30:3c:5d:47:fc:9a:16:bc:c3:37: + 96:41:51:8e:11:4b:54:f8:28:be:d0:8c:be:f0:30: + 38:1e:f3:b0:26:f8:66:47:63:6d:de:71:26:47:8f: + 38:47:53:d1:46:1d:b4:e3:dc:00:ea:45:ac:bd:bc: + 71:d9:aa:6f:00:db:db:cd:30:3a:79:4f:5f:4c:47: + f8:1d:ef:5b:c2:c4:9d:60:3b:b1:b2:43:91:d8:a4: + 33:4e:ea:b3:d6:27:4f:ad:25:8a:a5:c6:f4:d5:d0: + a6:ae:74:05:64:57:88:b5:44:55:d4:2d:2a:3a:3e: + f8:b8:bd:e9:32:0a:02:94:64:c4:16:3a:50:f1:4a: + ae:e7:79:33:af:0c:20:07:7f:e8:df:04:39:c2:69: + 02:6c:63:52:fa:77:c1:1b:c8:74:87:c8:b9:93:18: + 50:54:35:4b:69:4e:bc:3b:d3:49:2e:1f:dc:c1:d2: + 52:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 40:C2:BD:27:8E:CC:34:83:30:A2:33:D7:FB:6C:B3:F0:B4:2C:80:CE + X509v3 Authority Key Identifier: + keyid:3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 08:7e:6c:93:10:c8:38:b8:96:a9:90:4b:ff:a1:5f:4f:04:ef: + 6c:3e:9c:88:06:c9:50:8f:a6:73:f7:57:31:1b:be:bc:e4:2f: + db:f8:ba:d3:5b:e0:b4:e7:e6:79:62:0e:0c:a2:d7:6a:63:73: + 31:b5:f5:a8:48:a4:3b:08:2d:a2:5d:90:d7:b4:7c:25:4f:11: + 56:30:c4:b6:44:9d:7b:2c:9d:e5:5e:e6:ef:0c:61:aa:bf:e4: + 2a:1b:ee:84:9e:b8:83:7d:c1:43:ce:44:a7:13:70:0d:91:1f: + f4:c8:13:ad:83:60:d9:d8:72:a8:73:24:1e:b5:ac:22:0e:ca: + 17:89:62:58:44:1b:ab:89:25:01:00:0f:cd:c4:1b:62:db:51: + b4:d3:0f:51:2a:9b:f4:bc:73:fc:76:ce:36:a4:cd:d9:d8:2c: + ea:ae:9b:f5:2a:b2:90:d1:4d:75:18:8a:3f:8a:41:90:23:7d: + 5b:4b:fe:a4:03:58:9b:46:b2:c3:60:60:83:f8:7d:50:41:ce: + c2:a1:90:c3:bb:ef:02:2f:d2:15:54:ee:44:15:d9:0a:ae:a7: + 8a:33:ed:b1:2d:76:36:26:dc:04:eb:9f:f7:61:1f:15:dc:87: + 6f:ee:46:96:28:ad:a1:26:7d:0a:09:a7:2e:04:a3:8d:bc:f8: + bc:04:30:01 +-----BEGIN CERTIFICATE----- +MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3 +MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE +CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD +EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD +BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv +K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e +cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY +pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n +eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB +AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv +9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n +b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG +CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz +91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2 +RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi +DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 +GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x +LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: + 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: + e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: + c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: + 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: + 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: + a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: + 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: + 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: + b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: + 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: + 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: + 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: + 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: + 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: + 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: + 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: + e0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + Signature Algorithm: sha256WithRSAEncryption + 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d: + a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee: + cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7: + ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11: + ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85: + 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02: + 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e: + ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1: + 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd: + ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33: + ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33: + ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5: + 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43: + 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c: + f7:ea:1c:f5 +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- diff --git a/certs/Go-Daddy-Root-Certificate-Authority-G2.pem b/certs/Go-Daddy-Root-Certificate-Authority-G2.pem deleted file mode 100644 index c61f300..0000000 --- a/certs/Go-Daddy-Root-Certificate-Authority-G2.pem +++ /dev/null @@ -1,30 +0,0 @@ -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- diff --git a/certs/ISRG-Root-X1.pem b/certs/ISRG-Root-X1.pem deleted file mode 100644 index 995c95d..0000000 --- a/certs/ISRG-Root-X1.pem +++ /dev/null @@ -1,38 +0,0 @@ -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- diff --git a/certs/ISRG-Root-X2.pem b/certs/ISRG-Root-X2.pem deleted file mode 100644 index 9cca880..0000000 --- a/certs/ISRG-Root-X2.pem +++ /dev/null @@ -1,21 +0,0 @@ -# Issuer: CN=ISRG Root X2 O=Internet Security Research Group -# Subject: CN=ISRG Root X2 O=Internet Security Research Group -# Label: "ISRG Root X2" -# Serial: 87493402998870891108772069816698636114 -# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 -# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af -# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 ------BEGIN CERTIFICATE----- -MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw -CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg -R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 -MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT -ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw -EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW -+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 -ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI -zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW -tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 -/q4AaOeMSQ+2b1tbFfLn ------END CERTIFICATE----- diff --git a/certs/Makefile b/certs/Makefile deleted file mode 100644 index 3ccad6e..0000000 --- a/certs/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# Makefile to check certificates - -CURL = curl \ - --capath /dev/null \ - --connect-timeout 5 \ - --output /dev/null \ - --silent - -DOMAINS_DUAL = \ - api.macvendors.com/GTS-Root-R4 \ - api.telegram.org/Go-Daddy-Root-Certificate-Authority-G2 \ - cloudflare-dns.com/DigiCert-Global-Root-G2 \ - dns.google/GTS-Root-R4 \ - dns.quad9.net/DigiCert-Global-Root-G3 \ - git.eworm.de/ISRG-Root-X2 \ - lists.blocklist.de/Certum-Trusted-Network-CA \ - matrix.org/GTS-Root-R4 \ - raw.githubusercontent.com/USERTrust-RSA-Certification-Authority \ - rsc.eworm.de/ISRG-Root-X2 \ - upgrade.mikrotik.com/ISRG-Root-X1 -DOMAINS_IPV4 = \ - 1.1.1.1/DigiCert-Global-Root-G2 \ - 8.8.8.8/GTS-Root-R1 \ - 9.9.9.9/DigiCert-Global-Root-G3 \ - api.mullvad.net/ISRG-Root-X1 \ - ipv4.showipv6.de/ISRG-Root-X1 \ - ipv4.tunnelbroker.net/Starfield-Root-Certificate-Authority-G2 \ - mkcert.org/ISRG-Root-X1 \ - ntfy.sh/ISRG-Root-X1 \ - www.dshield.org/ISRG-Root-X1 \ - www.spamhaus.org/GTS-Root-R4 -DOMAINS_IPV6 = \ - [2606\:4700\:4700\:\:1111]/DigiCert-Global-Root-G2 \ - [2001\:4860\:4860\:\:8888]/GTS-Root-R1 \ - [2620\:fe\:\:9]/DigiCert-Global-Root-G3 \ - ipv6.showipv6.de/ISRG-Root-X1 - -.PHONY: $(DOMAINS_DUAL) $(DOMAINS_IPV4) $(DOMAINS_IPV6) - -all: $(DOMAINS_DUAL) $(DOMAINS_IPV4) $(DOMAINS_IPV6) - -$(DOMAINS_DUAL): -ifndef NOIPV4 - $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) -endif -ifndef NOIPV6 - $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) -endif - -$(DOMAINS_IPV4): -ifndef NOIPV4 - $(CURL) -4 --cacert $(notdir $@).pem https://$(dir $@) -endif - -$(DOMAINS_IPV6): -ifndef NOIPV6 - $(CURL) -6 --cacert $(notdir $@).pem https://$(dir $@) -endif diff --git a/certs/R3.pem b/certs/R3.pem new file mode 100644 index 0000000..ac322ec --- /dev/null +++ b/certs/R3.pem @@ -0,0 +1,314 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 91:2b:08:4a:cf:0c:18:a7:53:f6:d6:2e:25:a7:5f:5a + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Sep 4 00:00:00 2020 GMT + Not After : Sep 15 16:00:00 2025 GMT + Subject: C = US, O = Let's Encrypt, CN = R3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bb:02:15:28:cc:f6:a0:94:d3:0f:12:ec:8d:55: + 92:c3:f8:82:f1:99:a6:7a:42:88:a7:5d:26:aa:b5: + 2b:b9:c5:4c:b1:af:8e:6b:f9:75:c8:a3:d7:0f:47: + 94:14:55:35:57:8c:9e:a8:a2:39:19:f5:82:3c:42: + a9:4e:6e:f5:3b:c3:2e:db:8d:c0:b0:5c:f3:59:38: + e7:ed:cf:69:f0:5a:0b:1b:be:c0:94:24:25:87:fa: + 37:71:b3:13:e7:1c:ac:e1:9b:ef:db:e4:3b:45:52: + 45:96:a9:c1:53:ce:34:c8:52:ee:b5:ae:ed:8f:de: + 60:70:e2:a5:54:ab:b6:6d:0e:97:a5:40:34:6b:2b: + d3:bc:66:eb:66:34:7c:fa:6b:8b:8f:57:29:99:f8: + 30:17:5d:ba:72:6f:fb:81:c5:ad:d2:86:58:3d:17: + c7:e7:09:bb:f1:2b:f7:86:dc:c1:da:71:5d:d4:46: + e3:cc:ad:25:c1:88:bc:60:67:75:66:b3:f1:18:f7: + a2:5c:e6:53:ff:3a:88:b6:47:a5:ff:13:18:ea:98: + 09:77:3f:9d:53:f9:cf:01:e5:f5:a6:70:17:14:af: + 63:a4:ff:99:b3:93:9d:dc:53:a7:06:fe:48:85:1d: + a1:69:ae:25:75:bb:13:cc:52:03:f5:ed:51:a1:8b: + db:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6 + X509v3 Authority Key Identifier: + keyid:79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + + Authority Information Access: + CA Issuers - URI:http://x1.i.lencr.org/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://x1.c.lencr.org/ + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + + Signature Algorithm: sha256WithRSAEncryption + 85:ca:4e:47:3e:a3:f7:85:44:85:bc:d5:67:78:b2:98:63:ad: + 75:4d:1e:96:3d:33:65:72:54:2d:81:a0:ea:c3:ed:f8:20:bf: + 5f:cc:b7:70:00:b7:6e:3b:f6:5e:94:de:e4:20:9f:a6:ef:8b: + b2:03:e7:a2:b5:16:3c:91:ce:b4:ed:39:02:e7:7c:25:8a:47: + e6:65:6e:3f:46:f4:d9:f0:ce:94:2b:ee:54:ce:12:bc:8c:27: + 4b:b8:c1:98:2f:a2:af:cd:71:91:4a:08:b7:c8:b8:23:7b:04: + 2d:08:f9:08:57:3e:83:d9:04:33:0a:47:21:78:09:82:27:c3: + 2a:c8:9b:b9:ce:5c:f2:64:c8:c0:be:79:c0:4f:8e:6d:44:0c: + 5e:92:bb:2e:f7:8b:10:e1:e8:1d:44:29:db:59:20:ed:63:b9: + 21:f8:12:26:94:93:57:a0:1d:65:04:c1:0a:22:ae:10:0d:43: + 97:a1:18:1f:7e:e0:e0:86:37:b5:5a:b1:bd:30:bf:87:6e:2b: + 2a:ff:21:4e:1b:05:c3:f5:18:97:f0:5e:ac:c3:a5:b8:6a:f0: + 2e:bc:3b:33:b9:ee:4b:de:cc:fc:e4:af:84:0b:86:3f:c0:55: + 43:36:f6:68:e1:36:17:6a:8e:99:d1:ff:a5:40:a7:34:b7:c0: + d0:63:39:35:39:75:6e:f2:ba:76:c8:93:02:e9:a9:4b:6c:17: + ce:0c:02:d9:bd:81:fb:9f:b7:68:d4:06:65:b3:82:3d:77:53: + f8:8e:79:03:ad:0a:31:07:75:2a:43:d8:55:97:72:c4:29:0e: + f7:c4:5d:4e:c8:ae:46:84:30:d7:f2:85:5f:18:a1:79:bb:e7: + 5e:70:8b:07:e1:86:93:c3:b9:8f:dc:61:71:25:2a:af:df:ed: + 25:50:52:68:8b:92:dc:e5:d6:b5:e3:da:7d:d0:87:6c:84:21: + 31:ae:82:f5:fb:b9:ab:c8:89:17:3d:e1:4c:e5:38:0e:f6:bd: + 2b:bd:96:81:14:eb:d5:db:3d:20:a7:7e:59:d3:e2:f8:58:f9: + 5b:b8:48:cd:fe:5c:4f:16:29:fe:1e:55:23:af:c8:11:b0:8d: + ea:7c:93:90:17:2f:fd:ac:a2:09:47:46:3f:f0:e9:b0:b7:ff: + 28:4d:68:32:d6:67:5e:1e:69:a3:93:b8:f5:9d:8b:2f:0b:d2: + 52:43:a6:6f:32:57:65:4d:32:81:df:38:53:85:5d:7e:5d:66: + 29:ea:b8:dd:e4:95:b5:cd:b5:56:12:42:cd:c4:4e:c6:25:38: + 44:50:6d:ec:ce:00:55:18:fe:e9:49:64:d4:4e:ca:97:9c:b4: + 5b:c0:73:a8:ab:b8:47:c2 +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b + Signature Algorithm: sha1WithRSAEncryption + Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3 + Validity + Not Before: Sep 30 21:12:19 2000 GMT + Not After : Sep 30 14:01:15 2021 GMT + Subject: O = Digital Signature Trust Co., CN = DST Root CA X3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:df:af:e9:97:50:08:83:57:b4:cc:62:65:f6:90: + 82:ec:c7:d3:2c:6b:30:ca:5b:ec:d9:c3:7d:c7:40: + c1:18:14:8b:e0:e8:33:76:49:2a:e3:3f:21:49:93: + ac:4e:0e:af:3e:48:cb:65:ee:fc:d3:21:0f:65:d2: + 2a:d9:32:8f:8c:e5:f7:77:b0:12:7b:b5:95:c0:89: + a3:a9:ba:ed:73:2e:7a:0c:06:32:83:a2:7e:8a:14: + 30:cd:11:a0:e1:2a:38:b9:79:0a:31:fd:50:bd:80: + 65:df:b7:51:63:83:c8:e2:88:61:ea:4b:61:81:ec: + 52:6b:b9:a2:e2:4b:1a:28:9f:48:a3:9e:0c:da:09: + 8e:3e:17:2e:1e:dd:20:df:5b:c6:2a:8a:ab:2e:bd: + 70:ad:c5:0b:1a:25:90:74:72:c5:7b:6a:ab:34:d6: + 30:89:ff:e5:68:13:7b:54:0b:c8:d6:ae:ec:5a:9c: + 92:1e:3d:64:b3:8c:c6:df:bf:c9:41:70:ec:16:72: + d5:26:ec:38:55:39:43:d0:fc:fd:18:5c:40:f1:97: + eb:d5:9a:9b:8d:1d:ba:da:25:b9:c6:d8:df:c1:15: + 02:3a:ab:da:6e:f1:3e:2e:f5:5c:08:9c:3c:d6:83: + 69:e4:10:9b:19:2a:b6:29:57:e3:e5:3d:9b:9f:f0: + 02:5d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 + Signature Algorithm: sha1WithRSAEncryption + a3:1a:2c:9b:17:00:5c:a9:1e:ee:28:66:37:3a:bf:83:c7:3f: + 4b:c3:09:a0:95:20:5d:e3:d9:59:44:d2:3e:0d:3e:bd:8a:4b: + a0:74:1f:ce:10:82:9c:74:1a:1d:7e:98:1a:dd:cb:13:4b:b3: + 20:44:e4:91:e9:cc:fc:7d:a5:db:6a:e5:fe:e6:fd:e0:4e:dd: + b7:00:3a:b5:70:49:af:f2:e5:eb:02:f1:d1:02:8b:19:cb:94: + 3a:5e:48:c4:18:1e:58:19:5f:1e:02:5a:f0:0c:f1:b1:ad:a9: + dc:59:86:8b:6e:e9:91:f5:86:ca:fa:b9:66:33:aa:59:5b:ce: + e2:a7:16:73:47:cb:2b:cc:99:b0:37:48:cf:e3:56:4b:f5:cf: + 0f:0c:72:32:87:c6:f0:44:bb:53:72:6d:43:f5:26:48:9a:52: + 67:b7:58:ab:fe:67:76:71:78:db:0d:a2:56:14:13:39:24:31: + 85:a2:a8:02:5a:30:47:e1:dd:50:07:bc:02:09:90:00:eb:64: + 63:60:9b:16:bc:88:c9:12:e6:d2:7d:91:8b:f9:3d:32:8d:65: + b4:e9:7c:b1:57:76:ea:c5:b6:28:39:bf:15:65:1c:c8:f6:77: + 96:6a:0a:8d:77:0b:d8:91:0b:04:8e:07:db:29:b6:0a:ee:9d: + 82:35:35:10 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- diff --git a/certs/Starfield Secure Certificate Authority - G2.pem b/certs/Starfield Secure Certificate Authority - G2.pem new file mode 100644 index 0000000..7772e6b --- /dev/null +++ b/certs/Starfield Secure Certificate Authority - G2.pem @@ -0,0 +1,179 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certs.starfieldtech.com/repository/, CN = Starfield Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:e5:90:66:4b:ec:f9:46:71:a9:20:83:be:e9:6c: + bf:4a:c9:48:69:81:75:4e:6d:24:f6:cb:17:13:f8: + b0:71:59:84:7a:6b:2b:85:a4:34:b5:16:e5:cb:cc: + e9:41:70:2c:a4:2e:d6:fa:32:7d:e1:a8:de:94:10: + ac:31:c1:c0:d8:6a:ff:59:27:ab:76:d6:fc:0b:74: + 6b:b8:a7:ae:3f:c4:54:f4:b4:31:44:dd:93:56:8c: + a4:4c:5e:9b:89:cb:24:83:9b:e2:57:7d:b7:d8:12: + 1f:c9:85:6d:f4:d1:80:f1:50:9b:87:ae:d4:0b:10: + 05:fb:27:ba:28:6d:17:e9:0e:d6:4d:b9:39:55:06: + ff:0a:24:05:7e:2f:c6:1d:72:6c:d4:8b:29:8c:57: + 7d:da:d9:eb:66:1a:d3:4f:a7:df:7f:52:c4:30:c5: + a5:c9:0e:02:c5:53:bf:77:38:68:06:24:c3:66:c8: + 37:7e:30:1e:45:71:23:35:ff:90:d8:2a:9d:8d:e7: + b0:92:4d:3c:7f:2a:0a:93:dc:cd:16:46:65:f7:60: + 84:8b:76:4b:91:27:73:14:92:e0:ea:ee:8f:16:ea: + 8d:0e:3e:76:17:bf:7d:89:80:80:44:43:e7:2d:e0: + 43:09:75:da:36:e8:ad:db:89:3a:f5:5d:12:8e:23: + 04:83 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 25:45:81:68:50:26:38:3D:3B:2D:2C:BE:CD:6A:D9:B6:3D:B3:66:63 + X509v3 Authority Key Identifier: + keyid:7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 56:65:ca:fe:f3:3f:0a:a8:93:8b:18:c7:de:43:69:13:34:20: + be:4e:5f:78:a8:6b:9c:db:6a:4d:41:db:c1:13:ec:dc:31:00: + 22:5e:f7:00:9e:0c:e0:34:65:34:f9:b1:3a:4e:48:c8:12:81: + 88:5c:5b:3e:08:53:7a:f7:1a:64:df:b8:50:61:cc:53:51:40: + 29:4b:c2:f4:ae:3a:5f:e4:ca:ad:26:cc:4e:61:43:e5:fd:57: + a6:37:70:ce:43:2b:b0:94:c3:92:e9:e1:5f:aa:10:49:b7:69: + e4:e0:d0:1f:64:a4:2b:cd:1f:6f:a0:f8:84:24:18:ce:79:3d: + a9:91:bf:54:18:13:89:99:54:11:0d:55:c5:26:0b:79:4f:5a: + 1c:6e:f9:63:db:14:80:a4:07:ab:fa:b2:a5:b9:88:dd:91:fe: + 65:3b:a4:a3:79:be:89:4d:e1:d0:b0:f4:c8:17:0c:0a:96:14: + 7c:09:b7:6c:e1:c2:d8:55:d4:18:a0:aa:41:69:70:24:a3:b9: + ef:e9:5a:dc:3e:eb:94:4a:f0:b7:de:5f:0e:76:fa:fb:fb:69: + 03:45:40:50:ee:72:0c:a4:12:86:81:cd:13:d1:4e:c4:3c:ca: + 4e:0d:d2:26:f1:00:b7:b4:a6:a2:e1:6e:7a:81:fd:30:ac:7a: + 1f:c7:59:7b +-----BEGIN CERTIFICATE----- +MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw +MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk +dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF +pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE +3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV +Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ +MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX +v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB +Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ +zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB +BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo +LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo +LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF +BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN +QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 +rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO +eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ +sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ +7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: + d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: + 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: + 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: + dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: + 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: + f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: + 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: + b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: + 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: + 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: + 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: + 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: + c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: + 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: + a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: + 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: + 90:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + Signature Algorithm: sha256WithRSAEncryption + 11:59:fa:25:4f:03:6f:94:99:3b:9a:1f:82:85:39:d4:76:05: + 94:5e:e1:28:93:6d:62:5d:09:c2:a0:a8:d4:b0:75:38:f1:34: + 6a:9d:e4:9f:8a:86:26:51:e6:2c:d1:c6:2d:6e:95:20:4a:92: + 01:ec:b8:8a:67:7b:31:e2:67:2e:8c:95:03:26:2e:43:9d:4a: + 31:f6:0e:b5:0c:bb:b7:e2:37:7f:22:ba:00:a3:0e:7b:52:fb: + 6b:bb:3b:c4:d3:79:51:4e:cd:90:f4:67:07:19:c8:3c:46:7a: + 0d:01:7d:c5:58:e7:6d:e6:85:30:17:9a:24:c4:10:e0:04:f7: + e0:f2:7f:d4:aa:0a:ff:42:1d:37:ed:94:e5:64:59:12:20:77: + 38:d3:32:3e:38:81:75:96:73:fa:68:8f:b1:cb:ce:1f:c5:ec: + fa:9c:7e:cf:7e:b1:f1:07:2d:b6:fc:bf:ca:a4:bf:d0:97:05: + 4a:bc:ea:18:28:02:90:bd:54:78:09:21:71:d3:d1:7d:1d:d9: + 16:b0:a9:61:3d:d0:0a:00:22:fc:c7:7b:cb:09:64:45:0b:3b: + 40:81:f7:7d:7c:32:f5:98:ca:58:8e:7d:2a:ee:90:59:73:64: + f9:36:74:5e:25:a1:f5:66:05:2e:7f:39:15:a9:2a:fb:50:8b: + 8e:85:69:f4 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- diff --git a/certs/Starfield-Root-Certificate-Authority-G2.pem b/certs/Starfield-Root-Certificate-Authority-G2.pem deleted file mode 100644 index 4e6774d..0000000 --- a/certs/Starfield-Root-Certificate-Authority-G2.pem +++ /dev/null @@ -1,30 +0,0 @@ -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- diff --git a/certs/USERTrust-RSA-Certification-Authority.pem b/certs/USERTrust-RSA-Certification-Authority.pem deleted file mode 100644 index 0fbeef6..0000000 --- a/certs/USERTrust-RSA-Certification-Authority.pem +++ /dev/null @@ -1,41 +0,0 @@ -# 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----- diff --git a/check-certificates b/check-certificates new file mode 100644 index 0000000..e54b915 --- /dev/null +++ b/check-certificates @@ -0,0 +1,128 @@ +#!rsc by RouterOS +# RouterOS script: check-certificates +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for certificate validity +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md + +:global CertRenewPass; +:global CertRenewTime; +:global CertRenewUrl; +:global Identity; + +:global CertificateAvailable +:global CertificateNameByCN; +:global IfThenElse; +:global LogPrintExit; +:global ParseKeyValueStore; +:global SendNotification; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +:local FormatExpire do={ + :global CharacterReplace; + :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; +} + +$WaitFullyConnected; + +:foreach Cert in=[ / certificate find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ + :local CertVal [ / certificate get $Cert ]; + + :do { + :if ([ :len $CertRenewUrl ] = 0) do={ + $LogPrintExit info ("No CertRenewUrl given.") true; + } + + :foreach Type in={ ".pem"; ".p12" } do={ + :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); + :do { + / tool fetch check-certificate=yes-without-crl \ + ($CertRenewUrl . $CertFileName) dst-path=$CertFileName; + $WaitForFile $CertFileName; + :foreach PassPhrase in=$CertRenewPass do={ + / certificate import file-name=$CertFileName passphrase=$PassPhrase; + } + / file remove [ find where name=$CertFileName ]; + + :foreach CertInChain in=[ / certificate find where name~("^" . $CertFileName . "_[0-9]+\$") common-name!=($CertVal->"common-name") ] do={ + $CertificateNameByCN [ / certificate get $CertInChain common-name ]; + } + } on-error={ + $LogPrintExit debug ("Could not download certificate file " . $CertFileName) false; + } + } + + :local CertNew [ / certificate find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; + :local CertNewVal [ / certificate get $CertNew ]; + + :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ + $LogPrintExit warning ("The certificate chain is not available!") false; + } + + :if ($Cert != $CertNew) do={ + $LogPrintExit debug ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; + + :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ + / certificate remove $CertNew; + $LogPrintExit warning ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; + } + + / ip service set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; + + :do { + / ip ipsec identity set certificate=($CertNewVal->"name") [ / ip ipsec identity find where certificate=($CertVal->"name") ]; + / ip ipsec identity set remote-certificate=($CertNewVal->"name") [ / ip ipsec identity find where remote-certificate=($CertVal->"name") ]; + } on-error={ + $LogPrintExit debug ("Setting IPSEC certificates failed. Package 'security' not installed?") false; + } + + :do { + / ip hotspot profile set ssl-certificate=($CertNewVal->"name") [ / ip hotspot profile find where ssl-certificate=($CertVal->"name") ]; + } on-error={ + $LogPrintExit debug ("Setting hotspot certificates failed. Package 'hotspot' not installed?") false; + } + + / certificate remove $Cert; + / certificate set $CertNew name=($CertVal->"name"); + } + + $SendNotification ([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed") \ + ("A certificate on " . $Identity . " has been renewed.\n\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ + "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]) "" "" "true"; + $LogPrintExit info ("The certificate " . ($CertVal->"name") . " has been renewed.") false; + } on-error={ + $LogPrintExit debug ("Could not renew certificate " . ($CertVal->"name") . ".") false; + } +} + +:foreach Cert in=[ / certificate find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ + :local CertVal [ / certificate get $Cert ]; + + :if ([ :len [ / certificate scep-server find where ca-cert=($CertVal->"ca") ] ] > 0) do={ + $LogPrintExit debug ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; + } else={ + :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; + + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Certificate warning!") \ + ("A certificate on " . $Identity . " " . $State . ".\n\n" . \ + "Name: " . ($CertVal->"name") . "\n" . \ + "CommonName: " . ($CertVal->"common-name") . "\n" . \ + "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ + "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ + "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ + "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ + "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]); + $LogPrintExit info ("The certificate " . ($CertVal->"name") . " " . $State . \ + ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; + } +} diff --git a/check-certificates.rsc b/check-certificates.rsc deleted file mode 100644 index be8e4df..0000000 --- a/check-certificates.rsc +++ /dev/null @@ -1,242 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-certificates -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch -# -# check for certificate validity -# https://rsc.eworm.de/doc/check-certificates.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CertRenewTime; - :global CertRenewUrl; - :global CertWarnTime; - :global Identity; - - :global CertificateAvailable - :global EscapeForRegEx; - :global IfThenElse; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitFullyConnected; - - :local CheckCertificatesDownloadImport do={ - :local ScriptName [ :tostr $1 ]; - :local CertName [ :tostr $2 ]; - :local FetchName [ :tostr $3 ]; - - :global CertRenewUrl; - :global CertRenewPass; - - :global CertificateNameByCN; - :global EscapeForRegEx; - :global FetchUserAgentStr; - :global LogPrint; - :global RmFile; - :global UrlEncode; - :global WaitForFile; - - :foreach Type in={ "p12"; "pem" } do={ - :local CertFileName ([ $UrlEncode $FetchName ] . "." . $Type); - $LogPrint debug $ScriptName ("Trying type '" . $Type . "' for '" . $CertName . \ - "' (file '" . $CertFileName . "')..."); - - :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 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; - - :if ($DecryptionFailed = true) do={ - $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); - } - - :foreach CertInChain in=[ /certificate/find where common-name!=$CertName !private-key \ - name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ - !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $CertName ] . "(\\W|\$)")) \ - !(common-name=[]) ] do={ - $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; - } - - :return true; - } on-error={ - $LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'."); - } - } - - :return false; - } - - :local FormatInfo do={ - :local Cert $1; - - :global FormatLine; - :global FormatMultiLines; - :global IfThenElse; - - :local FormatExpire do={ - :global CharacterReplace; - :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; - } - - :local FormatCertChain do={ - :local Cert $1; - - :global EitherOr; - :global ParseKeyValueStore; - - :local CertVal [ /certificate/get $Cert ]; - - :if ([ :typeof ($CertVal->"issuer") ] = "nothing") do={ - :return "self-signed"; - } - - :local Return ""; - :for I from=0 to=5 do={ - :set Return ($Return . [ $EitherOr ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") \ - ([ $ParseKeyValueStore (($CertVal->"issuer")->0) ]->"CN") ]); - :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; - :if (($CertVal->"akid") = "" || ($CertVal->"akid") = ($CertVal->"skid")) do={ - :return $Return; - } - :set Return ($Return . " -> "); - } - :return ($Return . "..."); - } - - :local CertVal [ /certificate/get $Cert ]; - - :return ( \ - [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ - [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ - [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \ - [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \ - [ $IfThenElse ([ :len ($CertVal->"ca") ] > 0) [ $FormatLine "Issuer" ($CertVal->"ca") ] [ $FormatLine "Issuer chain" [ $FormatCertChain $Cert ] ] ] . "\n" . \ - "Validity:\n" . \ - [ $FormatLine " from" ($CertVal->"invalid-before") ] . "\n" . \ - [ $FormatLine " to" ($CertVal->"invalid-after") ] . "\n" . \ - [ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]); - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ - :local CertVal [ /certificate/get $Cert ]; - :local LastName; - :local FetchName; - - :do { - :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrint info $ScriptName ("No CertRenewUrl given."); - :error false; - } - $LogPrint info $ScriptName ("Attempting to renew certificate '" . ($CertVal->"name") . "'."); - - :local ImportSuccess false; - :set LastName ($CertVal->"common-name"); - :set FetchName $LastName; - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; - :foreach SAN in=($CertVal->"subject-alt-name") do={ - :if ($ImportSuccess = false) do={ - :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; - :set FetchName $LastName; - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; - :if ($ImportSuccess = false && [ :pick $LastName 0 2 ] = "*.") do={ - :set FetchName ("star." . [ :pick $LastName 2 [ :len $LastName ] ]); - :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName $FetchName ]; - } - } - } - :if ($ImportSuccess = false) do={ :error false; } - - :if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ - $LogPrint debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was updated in place."); - :set CertVal [ /certificate/get $Cert ]; - } else={ - $LogPrint debug $ScriptName ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced."); - - :local CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $FetchName ] ] . "\\.(p12|pem)_[0-9]+\$") \ - (common-name=($CertVal->"common-name") or subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $LastName ] . "(\\W|\$)")) \ - fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; - :local CertNewVal [ /certificate/get $CertNew ]; - - :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ - $LogPrint warning $ScriptName ("The certificate chain is not available!"); - } - - :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ - /certificate/remove $CertNew; - $LogPrint warning $ScriptName ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew."); - :error false; - } - - /ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - - /ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - /ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ]; - - /ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ]; - - /certificate/remove $Cert; - /certificate/set $CertNew name=($CertVal->"name"); - :set Cert $CertNew; - :set CertVal [ /certificate/get $CertNew ]; - } - - $SendNotification2 ({ origin=$ScriptName; silent=true; \ - subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed: " . ($CertVal->"name")); \ - message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $Cert ]) }); - $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' has been renewed."); - } on-error={ - $LogPrint debug $ScriptName ("Could not renew certificate '" . ($CertVal->"name") . "'."); - } - } - - :foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \ - expires-after<$CertWarnTime !(fingerprint=[]) ] do={ - :local CertVal [ /certificate/get $Cert ]; - - :if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={ - $LogPrint debug $ScriptName ("Certificate '" . ($CertVal->"name") . "' is handled by SCEP, skipping."); - } else={ - :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; - - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ - message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) }); - $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . "."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/check-health b/check-health new file mode 100644 index 0000000..7fa45cb --- /dev/null +++ b/check-health @@ -0,0 +1,95 @@ +#!rsc by RouterOS +# RouterOS script: check-health +# Copyright (c) 2019-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for RouterOS health state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md + +:global CheckHealthLast; +:global CheckHealthTemperature; +:global CheckHealthTemperatureDeviation; +:global CheckHealthTemperatureNotified; +:global CheckHealthVoltagePercent; +:global Identity; + +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; + +:local FormatVoltage do={ + :local Voltage [ :tonum $1 ]; + :return (($Voltage / 10) . "." . [ :pick $Voltage ([ :len $Voltage ] - 1) ] . "V"); +} + +:local CheckHealthCurrent [ / system health get ]; + +:if ([ :len $CheckHealthCurrent ] = 0) do={ + $LogPrintExit error ("Your device does not provide any health values.") true; +} + +:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified [ :toarray "" ]; +} + +:foreach Name,Voltage in=$CheckHealthCurrent do={ + :if ($Name ~ "(battery|voltage)" && \ + [ :typeof ($CheckHealthLast->$Name) ] = "num" && \ + [ :typeof $Voltage ] = "num") do={ + :if ($CheckHealthLast->$Name * (100 + $CheckHealthVoltagePercent) < $Voltage * 100 || \ + $CheckHealthLast->$Name * 100 > $Voltage * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification ([ $SymbolForNotification "high-voltage-sign" ] . "Health warning: " . $Name) \ + ("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ + "old value: " . [ $FormatVoltage ($CheckHealthLast->$Name) ] . "\n" . \ + "new value: " . [ $FormatVoltage $Voltage ]); + } + } +} + +:foreach Name,PSU in=$CheckHealthCurrent do={ + :if ($Name ~ "psu.*-state" && \ + [ :typeof ($CheckHealthLast->$Name) ] = "str" && \ + [ :typeof $PSU ] = "str") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $PSU != "ok") do={ + $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name) \ + ("The power supply unit '" . $Name . "' on " . $Identity . " failed!"); + } + :if ($CheckHealthLast->$Name != "ok" && \ + $PSU = "ok") do={ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ + ("The power supply unit '" . $Name . "' on " . $Identity . " recovered!"); + } + } +} + +:foreach Name,Temperature in=$CheckHealthCurrent do={ + :if ($Name ~ "temperature" && \ + [ :typeof $Temperature ] = "num") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrintExit info ("No threshold given for " . $Name . ", assuming 50C.") false; + :set ($CheckHealthTemperature->$Name) 50; + } + :local Validate [ / system health get $Name ]; + :while ($Temperature != $Validate) do={ + :set Temperature $Validate; + :set Validate [ / system health get $Name ]; + } + :if ($Temperature > $CheckHealthTemperature->$Name && \ + $CheckHealthTemperatureNotified->$Name != true) do={ + $SendNotification ([ $SymbolForNotification "fire" ] . "Health warning: " . $Name) \ + ("The " . $Name . " on " . $Identity . " is above threshold: " . \ + $Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Name) true; + } + :if ($Temperature <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ + $CheckHealthTemperatureNotified->$Name = true) do={ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name) \ + ("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ + $Temperature . "\C2\B0" . "C"); + :set ($CheckHealthTemperatureNotified->$Name) false; + } + } +} + +:set CheckHealthLast $CheckHealthCurrent; diff --git a/check-health.d/state.rsc b/check-health.d/state.rsc deleted file mode 100644 index 2991935..0000000 --- a/check-health.d/state.rsc +++ /dev/null @@ -1,48 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-health.d/state -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# check for RouterOS health state - state plugin -# https://rsc.eworm.de/doc/check-health.md - -:global CheckHealthPlugins; - -:set ($CheckHealthPlugins->[ :jobname ]) do={ - :local FuncName [ :tostr $0 ]; - - :global CheckHealthLast; - :global Identity; - - :global LogPrint; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ :len [ /system/health/find where type="" name~"-state\$"] ] = 0) do={ - $LogPrint debug $FuncName ("Your device does not provide any state health values."); - :return false; - } - - :foreach State in=[ /system/health/find where type="" name~"-state\$" ] do={ - :local Name [ /system/health/get $State name ]; - :local Value [ /system/health/get $State value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ($CheckHealthLast->$Name = "ok" && \ - $Value != "ok") do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ - message=("The device '" . $Name . "' on " . $Identity . " failed!") }); - } - :if ($CheckHealthLast->$Name != "ok" && \ - $Value = "ok") do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The device '" . $Name . "' on " . $Identity . " recovered!") }); - } - } - :set ($CheckHealthLast->$Name) $Value; - } -} diff --git a/check-health.d/temperature.rsc b/check-health.d/temperature.rsc deleted file mode 100644 index a2f632d..0000000 --- a/check-health.d/temperature.rsc +++ /dev/null @@ -1,74 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-health.d/temperature -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# check for RouterOS health state - temperature plugin -# https://rsc.eworm.de/doc/check-health.md - -:global CheckHealthPlugins; - -:set ($CheckHealthPlugins->[ :jobname ]) do={ - :local FuncName [ :tostr $0 ]; - - :global CheckHealthLast; - :global CheckHealthTemperature; - :global CheckHealthTemperatureDeviation; - :global CheckHealthTemperatureNotified; - :global Identity; - - :global LogPrint; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ :len [ /system/health/find where type="C" ] ] = 0) do={ - $LogPrint debug $FuncName ("Your device does not provide any voltage health values."); - :return false; - } - - :local TempToNum do={ - :global CharacterReplace; - :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; - :return ($T->0 * 10 + $T->1); - } - - :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); - } - - :foreach Temperature in=[ /system/health/find where type="C" ] do={ - :local Name [ /system/health/get $Temperature name ]; - :local Value [ /system/health/get $Temperature value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrint info $FuncName ("No threshold given for " . $Name . ", assuming 50C."); - :set ($CheckHealthTemperature->$Name) 50; - } - :local Validate [ /system/health/get [ find where name=$Name ] value ]; - :while ($Value != $Validate) do={ - :set Value $Validate; - :set Validate [ /system/health/get [ find where name=$Name ] value ]; - } - :if ($Value > $CheckHealthTemperature->$Name && \ - $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) true; - } - :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) false; - } - } - :set ($CheckHealthLast->$Name) $Value; - } -} diff --git a/check-health.d/voltage.rsc b/check-health.d/voltage.rsc deleted file mode 100644 index 9071c88..0000000 --- a/check-health.d/voltage.rsc +++ /dev/null @@ -1,63 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-health.d/voltage -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# check for RouterOS health state - voltage plugin -# https://rsc.eworm.de/doc/check-health.md - -:global CheckHealthPlugins; - -:set ($CheckHealthPlugins->[ :jobname ]) do={ - :local FuncName [ :tostr $0 ]; - - :global CheckHealthLast; - :global CheckHealthVoltageLow; - :global CheckHealthVoltagePercent; - :global Identity; - - :global FormatLine; - :global IfThenElse; - :global LogPrint; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ :len [ /system/health/find where type="V" ] ] = 0) do={ - $LogPrint debug $FuncName ("Your device does not provide any voltage health values."); - :return false; - } - - :foreach Voltage in=[ /system/health/find where type="V" ] do={ - :local Name [ /system/health/get $Voltage name ]; - :local Value [ /system/health/get $Voltage value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :local NumCurr [ $TempToNum $Value ]; - :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; - - :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ - $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ - $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ - [ $FormatLine "new value" ($Value . " V") 12 ]) }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$FuncName; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); - } - } - } - :set ($CheckHealthLast->$Name) $Value; - } -} diff --git a/check-health.rsc b/check-health.rsc deleted file mode 100644 index f02a249..0000000 --- a/check-health.rsc +++ /dev/null @@ -1,110 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-health -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# check for RouterOS health state -# https://rsc.eworm.de/doc/check-health.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CheckHealthCPUUtilization; - :global CheckHealthCPUUtilizationNotified; - :global CheckHealthLast; - :global CheckHealthRAMUtilizationNotified; - :global Identity; - - :global FormatLine; - :global HumanReadableNum; - :global IfThenElse; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global ValidateSyntax; - - :local TempToNum do={ - :global CharacterReplace; - :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; - :return ($T->0 * 10 + $T->1); - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local Resource [ /system/resource/get ]; - - :set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); - :if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \ - message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") }); - :set CheckHealthCPUUtilizationNotified true; - } - :if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \ - message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") }); - :set CheckHealthCPUUtilizationNotified false; - } - - :local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory"); - :if ($CheckHealthRAMUtilization >=80 && $CheckHealthRAMUtilizationNotified != true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health warning: RAM utilization"); \ - message=("The RAM utilization on " . $Identity . " is at " . $CheckHealthRAMUtilization . "%!\n\n" . \ - [ $FormatLine "total" ([ $HumanReadableNum ($Resource->"total-memory") 1024 ] . "B") 8 ] . "\n" . \ - [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "B") 8 ] . "\n" . \ - [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "B") 8 ]) }); - :set CheckHealthRAMUtilizationNotified true; - } - :if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "card-file-box,chart-decreasing" ] . "Health recovery: RAM utilization"); \ - message=("The RAM utilization on " . $Identity . " decreased to " . $CheckHealthRAMUtilization . "%.") }); - :set CheckHealthRAMUtilizationNotified false; - } - - :local Plugins [ /system/script/find where name~"^check-health.d/." ]; - :if ([ :len $Plugins ] = 0) do={ - $LogPrint debug $ScriptName ("No plugins installed."); - :set ExitOK true; - :error true; - } - - :global CheckHealthPlugins ({}); - :if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast ({}); - } - - :foreach Plugin in=$Plugins do={ - :local PluginVal [ /system/script/get $Plugin ]; - :if ([ $ValidateSyntax ($PluginVal->"source") ] = true) do={ - :do { - /system/script/run $Plugin; - } on-error={ - $LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed to run."); - } - } else={ - $LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); - } - } - - :foreach PluginName,Discard in=$CheckHealthPlugins do={ - ($CheckHealthPlugins->$PluginName) \ - ("\$CheckHealthPlugins->\"" . $PluginName . "\""); - } - - :set CheckHealthPlugins; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade new file mode 100644 index 0000000..edbd5b1 --- /dev/null +++ b/check-lte-firmware-upgrade @@ -0,0 +1,41 @@ +#!rsc by RouterOS +# RouterOS script: check-lte-firmware-upgrade +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for LTE firmware upgrade, send notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md + +:global Identity; +:global SentLteFirmwareUpgradeNotification; + +:global CharacterReplace; +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; + +:foreach Interface in=[ / interface lte find ] do={ + :local IntName [ / interface lte get $Interface name ]; + :do { + :local Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; + + :if ($SentLteFirmwareUpgradeNotification = ($Firmware->"latest")) do={ + $LogPrintExit debug ("Already sent the LTE firmware upgrade notification for version " . \ + ($Firmware->"latest") . ".") false; + } else={ + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :local Info [ / interface lte info $Interface once as-value ]; + $SendNotification ([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade") \ + ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ + "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ + "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ + "Installed: " . ($Firmware->"installed") . "\n" . \ + "Available: " . ($Firmware->"latest")) "" "" "true"; + :set SentLteFirmwareUpgradeNotification ($Firmware->"latest"); + } + } + } on-error={ + $LogPrintExit debug ("Could not get latest LTE firmware version for interface " . \ + $IntName . ".") false; + } +} diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc deleted file mode 100644 index c5b6cb5..0000000 --- a/check-lte-firmware-upgrade.rsc +++ /dev/null @@ -1,107 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# check for LTE firmware upgrade, send notification -# https://rsc.eworm.de/doc/check-lte-firmware-upgrade.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global SentLteFirmwareUpgradeNotification; - - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ - :global SentLteFirmwareUpgradeNotification ({}); - } - - :local CheckInterface do={ - :local ScriptName $1; - :local Interface $2; - - :global Identity; - :global SentLteFirmwareUpgradeNotification; - - :global FormatLine; - :global IfThenElse; - :global LogPrint; - :global ScriptFromTerminal; - :global SendNotification2; - :global SymbolForNotification; - - :local IntName [ /interface/lte/get $Interface name ]; - :local Firmware; - :local Info; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ]; - :set Info [ /interface/lte/monitor $Interface once as-value ]; - } on-error={ - $LogPrint debug $ScriptName ("Could not get latest LTE firmware version for interface " . \ - $IntName . "."); - :return false; - } - - :if ([ :len ($Firmware->"latest") ] = 0) do={ - $LogPrint info $ScriptName ("An empty string is not a valid version."); - :return false; - } - - :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - $LogPrint info $ScriptName ("No firmware upgrade available for LTE interface " . $IntName . "."); - } - :return true; - } - - :if ([ $ScriptFromTerminal $ScriptName ] = true && \ - [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ - :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - /system/script/run unattended-lte-firmware-upgrade; - $LogPrint info $ScriptName ("Scheduled lte firmware upgrade for interface " . $IntName . "..."); - :return true; - } else={ - :put "Canceled..."; - } - } - - :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ - $LogPrint debug $ScriptName ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . "."); - :return false; - } - - $LogPrint info $ScriptName ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . "."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ - message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - [ $IfThenElse ([ :len ($Info->"manufacturer") ] > 0) ([ $FormatLine "Manufacturer" ($Info->"manufacturer") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($Info->"model") ] > 0) ([ $FormatLine "Model" ($Info->"model") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($Info->"revision") ] > 0) ([ $FormatLine "Revision" ($Info->"revision") ] . "\n") ] . \ - "Firmware version:\n" . \ - [ $FormatLine " Installed" ($Firmware->"installed") ] . "\n" . \ - [ $FormatLine " Available" ($Firmware->"latest") ]); silent=true }); - :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); - } - - :foreach Interface in=[ /interface/lte/find ] do={ - $CheckInterface $ScriptName $Interface; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/check-routeros-update b/check-routeros-update new file mode 100644 index 0000000..297f726 --- /dev/null +++ b/check-routeros-update @@ -0,0 +1,123 @@ +#!rsc by RouterOS +# RouterOS script: check-routeros-update +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check for RouterOS update, send notification and/or install +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md + +:global Identity; +:global SafeUpdateNeighbor; +:global SafeUpdatePatch; +:global SafeUpdateUrl; +:global SentRouterosUpdateNotification; + +:global DeviceInfo; +:global LogPrintExit; +:global ScriptFromTerminal; +:global SendNotification; +:global SymbolForNotification; +:global VersionToNum; + +:local DoUpdate do={ + :if ([ :len [ / system script find where name="packages-update" ] ] > 0) do={ + / system script run packages-update; + } else={ + / system package update install without-paging; + } + :error "Waiting for system to reboot."; +} + +:if ([ :len [ / system package find where name="wireless" disabled=no ] ] > 0) do={ + :if ([ / interface wireless cap get enabled ] = true && \ + [ / caps-man manager get enabled ] = false) do={ + $LogPrintExit error "System is managed by CAPsMAN, not checking." true; + } +} + +:if ([ :len [ / system scheduler find where name="reboot-for-update" ] ] > 0) do={ + :error "A reboot for update is already scheduled."; +} + +/ system package update check-for-updates without-paging; +:local Update [ / system package update get ]; + +:if ([ :len ($Update->"latest-version") ] = 0) do={ + $LogPrintExit info "An empty string is not a valid version." true; +} + +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; +:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); + +:if ($NumInstalled < $NumLatest) do={ + :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ + $LogPrintExit info ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ + ("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ + ", updating on " . $Identity . "...") $Link "" "true"; + $DoUpdate; + } + + :if ($SafeUpdateNeighbor = true && [ :len [ / ip neighbor find where \ + version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ + $LogPrintExit info ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ + ("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ + ", updating on " . $Identity . "...") $Link "" "true"; + $DoUpdate; + } + + :if ([ :len $SafeUpdateUrl ] > 0) do={ + :local Result; + :do { + :set Result [ / tool fetch check-certificate=yes-without-crl \ + ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ + "&latest=" . $Update->"latest-version") output=user as-value ]; + } on-error={ + $LogPrintExit warning ("Failed receiving safe version for " . $Update->"channel" . ".") false; + } + :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ + $LogPrintExit info ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ + ("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ + ", updating on " . $Identity . "...") $Link "" "true"; + $DoUpdate; + } + } + + :if ([ $ScriptFromTerminal "check-routeros-update" ] = true) do={ + :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + $DoUpdate; + } else={ + :put "Canceled..."; + } + } + + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit info ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . ".") true; + } + + $SendNotification ([ $SymbolForNotification "sparkles" ] . "RouterOS update") \ + ("A new RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ".\n\n" . \ + [ $DeviceInfo ]) $Link "" "true"; + :set SentRouterosUpdateNotification ($Update->"latest-version"); +} + +:if ($NumInstalled > $NumLatest) do={ + :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ + $LogPrintExit info ("Already sent the RouterOS downgrade notification for version " . \ + $Update->"latest-version" . ".") true; + } + + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "RouterOS version") \ + ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ + [ $DeviceInfo ]) $Link "" "true"; + $LogPrintExit info ("A different RouterOS version " . ($Update->"latest-version") . \ + " is available for downgrade.") false; + :set SentRouterosUpdateNotification ($Update->"latest-version"); +} diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc deleted file mode 100644 index 78161e4..0000000 --- a/check-routeros-update.rsc +++ /dev/null @@ -1,239 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-routeros-update -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch, scheduler -# -# check for RouterOS update, send notification and/or install -# https://rsc.eworm.de/doc/check-routeros-update.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - :global SafeUpdateAll; - :global SafeUpdateNeighbor; - :global SafeUpdateNeighborIdentity; - :global SafeUpdatePatch; - :global SafeUpdateUrl; - :global SentRouterosUpdateNotification; - - :global DeviceInfo; - :global EscapeForRegEx; - :global FetchUserAgentStr; - :global LogPrint; - :global ScriptFromTerminal; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global VersionToNum; - :global WaitFullyConnected; - - :local DoUpdate do={ - :local ScriptName [ :tostr $1 ]; - - :global LogPrint; - - :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ - /system/script/run packages-update; - } else={ - /system/package/update/install without-paging; - } - $LogPrint info $ScriptName ("Waiting for system to reboot."); - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ - :set ExitOK true; - :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 ]; - - :if (($Update->"installed-version") = ($Update->"latest-version")) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - $LogPrint info $ScriptName ("System is already up to date."); - } - :set ExitOK true; - :error true; - } - - :if ([ :len ($Update->"latest-version") ] = 0) do={ - $LogPrint info $ScriptName ("Received an empty version string from server."); - :set ExitOK true; - :error false; - } - - :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; - :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - :local BitMask [ $VersionToNum "255.255zero0" ]; - :local NumInstalledFeature ($NumInstalled & $BitMask); - :local NumLatestFeature ($NumLatest & $BitMask); - :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); - - :if ($NumLatest < [ $VersionToNum "7.0" ]) do={ - $LogPrint warning $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); - :set ExitOK true; - :error false; - } - - :if ($NumInstalled < $NumLatest) do={ - :if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={ - $LogPrint info $ScriptName ("Installing ALL versions automatically, including " . \ - $Update->"latest-version" . "..."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \ - "... Updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate $ScriptName; - :set ExitOK true; - :error true; - } - - :if ($SafeUpdatePatch = true && $NumInstalledFeature = $NumLatestFeature) do={ - $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating..."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate $ScriptName; - :set ExitOK true; - :error true; - } - - :if ($SafeUpdateNeighbor = true) do={ - :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ - version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; - :if ([ :len $Neighbors ] > 0) do={ - :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; - $LogPrint info $ScriptName ("Seen a neighbor (" . $Neighbor . ") running version " . \ - $Update->"latest-version" . " from " . $Update->"channel" . ", updating..."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Seen a neighbor (" . $Neighbor . ") running version " . $Update->"latest-version" . \ - " from " . $Update->"channel" . ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate $ScriptName; - :set ExitOK true; - :error true; - } - } - - :if ([ :len $SafeUpdateUrl ] > 0) do={ - :local Result; - :do { - :set Result [ /tool/fetch check-certificate=yes-without-crl \ - ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ - "&latest=" . $Update->"latest-version") http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ - output=user as-value ]; - } on-error={ - $LogPrint warning $ScriptName ("Failed receiving safe version for " . $Update->"channel" . "."); - } - :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is considered safe, updating..."); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate $ScriptName; - :set ExitOK true; - :error true; - } - } - - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :if (($Update->"channel") = "testing" && $NumInstalledFeature < $NumLatestFeature) do={ - :put ("This is a feature update in testing channel. Switch to channel 'stable'? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - /system/package/update/set channel=stable; - $LogPrint info $ScriptName ("Switched to channel 'stable', please re-run!"); - :set ExitOK true; - :error true; - } - } - - :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $DoUpdate $ScriptName; - :set ExitOK true; - :error true; - } else={ - :put "Canceled..."; - } - } - - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrint info $ScriptName ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . "."); - :set ExitOK true; - :error true; - } - - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ - message=("A new RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - :set SentRouterosUpdateNotification ($Update->"latest-version"); - } - - :if ($NumInstalled > $NumLatest) do={ - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrint info $ScriptName ("Already sent the RouterOS downgrade notification for version " . \ - $Update->"latest-version" . "."); - :set ExitOK true; - :error true; - } - - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version: " . $Update->"latest-version"); \ - message=("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - $LogPrint info $ScriptName ("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for downgrade."); - :set SentRouterosUpdateNotification ($Update->"latest-version"); - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/cloud-backup b/cloud-backup new file mode 100644 index 0000000..b4c9002 --- /dev/null +++ b/cloud-backup @@ -0,0 +1,40 @@ +#!rsc by RouterOS +# RouterOS script: cloud-backup +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# upload backup to MikroTik cloud +# https://git.eworm.de/cgit/routeros-scripts/about/doc/cloud-backup.md + +:global BackupPassword; +:global Identity; + +:global DeviceInfo; +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; + +:do { + # we are not interested in output, but print is + # required to fetch information from cloud + / system backup cloud print as-value; + :if ([ :len [ / system backup cloud find ] ] > 0) do={ + / system backup cloud upload-file action=create-and-upload \ + password=$BackupPassword replace=[ get ([ find ]->0) name ]; + } else={ + / system backup cloud upload-file action=create-and-upload \ + password=$BackupPassword; + } + :local Cloud [ / system backup cloud get ([ find ]->0) ]; + + $SendNotification ([ $SymbolForNotification "floppy-disk" ] . "Cloud backup") \ + ("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Name: " . $Cloud->"name" . "\n" . \ + "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ + "Download key: " . $Cloud->"secret-download-key") "" "" "true"; +} on-error={ + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed") \ + ("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]); + $LogPrintExit error ("Failed uploading backup for " . $Identity . " to cloud!") true; +} diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman new file mode 100644 index 0000000..fda401e --- /dev/null +++ b/collect-wireless-mac.capsman @@ -0,0 +1,70 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.capsman +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# +# !! Do not edit this file, it is generated from template! + +:global Identity; + +:global GetMacVendor; +:global LogPrintExit; +:global ScriptLock; +:global SendNotification; +:global SymbolForNotification; + +$ScriptLock "collect-wireless-mac.capsman"; + +:if ([ :len [ / caps-man access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ + / caps-man access-list add comment="--- collected above ---" disabled=yes; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; +} +:local PlaceBefore ([ / caps-man access-list find where comment="--- collected above ---" disabled ]->0); + +:foreach RegTbl in=[ / caps-man registration-table find ] do={ + :local Mac [ / caps-man registration-table get $RegTbl mac-address ]; + :local AccessList ([ / caps-man access-list find where mac-address=$Mac ]->0); + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } + } + :local RegEntry [ / caps-man registration-table find where mac-address=$Mac ]; + :local Interface [ / caps-man registration-table get $RegEntry interface ]; + :local Ssid [ / caps-man registration-table get $RegEntry ssid ]; + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor $Mac ]; + :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + $LogPrintExit info $Message false; + / caps-man access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ + ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $Interface . "\n" . \ + "SSID: " . $Ssid . "\n" . \ + "MAC: " . $Mac . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime); + } else={ + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / caps-man access-list get $AccessList comment ]) false; + } +} diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc deleted file mode 100644 index 17e09e3..0000000 --- a/collect-wireless-mac.capsman.rsc +++ /dev/null @@ -1,100 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=40 -# requires RouterOS, version=7.15 -# -# collect wireless mac adresses in access list -# https://rsc.eworm.de/doc/collect-wireless-mac.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - - :global EitherOr; - :global FormatLine; - :global FormatMultiLines; - :global GetMacVendor; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); - - :foreach Reg in=[ /caps-man/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /caps-man/registration-table/get $Reg ]; - } on-error={ - $LogPrint debug $ScriptName ("Device already gone... Ignoring."); - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]); - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease active-address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); - :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ - :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); - } - } - } - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrint info $ScriptName $Message; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Controller" $Identity ] . "\n" . \ - [ $FormatLine "Interface" ($RegVal->"interface") ] . "\n" . \ - [ $FormatLine "SSID" ($RegVal->"ssid") ] . "\n" . \ - [ $FormatLine "MAC" ($RegVal->"mac-address") ] . "\n" . \ - [ $FormatLine "Vendor" $Vendor ] . "\n" . \ - [ $FormatLine "Hostname" $HostName ] . "\n" . \ - [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ - [ $FormatLine "Date" $DateTime ]) }); - } - } else={ - $LogPrint debug $ScriptName ("No mac address available... Ignoring."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local new file mode 100644 index 0000000..f9c135c --- /dev/null +++ b/collect-wireless-mac.local @@ -0,0 +1,70 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.local +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# +# !! Do not edit this file, it is generated from template! + +:global Identity; + +:global GetMacVendor; +:global LogPrintExit; +:global ScriptLock; +:global SendNotification; +:global SymbolForNotification; + +$ScriptLock "collect-wireless-mac.local"; + +:if ([ :len [ / interface wireless access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ + / interface wireless access-list add comment="--- collected above ---" disabled=yes; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; +} +:local PlaceBefore ([ / interface wireless access-list find where comment="--- collected above ---" disabled ]->0); + +:foreach RegTbl in=[ / interface wireless registration-table find ] do={ + :local Mac [ / interface wireless registration-table get $RegTbl mac-address ]; + :local AccessList ([ / interface wireless access-list find where mac-address=$Mac ]->0); + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } + } + :local RegEntry [ / interface wireless registration-table find where mac-address=$Mac ]; + :local Interface [ / interface wireless registration-table get $RegEntry interface ]; + :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ]; + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor $Mac ]; + :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + $LogPrintExit info $Message false; + / interface wireless access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ + ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $Interface . "\n" . \ + "SSID: " . $Ssid . "\n" . \ + "MAC: " . $Mac . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime); + } else={ + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / interface wireless access-list get $AccessList comment ]) false; + } +} diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc deleted file mode 100644 index 4a38bfa..0000000 --- a/collect-wireless-mac.local.rsc +++ /dev/null @@ -1,101 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=40 -# requires RouterOS, version=7.15 -# -# collect wireless mac adresses in access list -# https://rsc.eworm.de/doc/collect-wireless-mac.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - - :global EitherOr; - :global FormatLine; - :global FormatMultiLines; - :global GetMacVendor; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); - } - :local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); - - :foreach Reg in=[ /interface/wireless/registration-table/find where ap=no ] do={ - :local RegVal; - :do { - :set RegVal [ /interface/wireless/registration-table/get $Reg ]; - } on-error={ - $LogPrint debug $ScriptName ("Device already gone... Ignoring."); - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wireless/access-list/get $AccessList comment ]); - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease active-address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); - :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ - :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); - } - } - } - :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrint info $ScriptName $Message; - /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Controller" $Identity ] . "\n" . \ - [ $FormatLine "Interface" ($RegVal->"interface") ] . "\n" . \ - [ $FormatLine "SSID" ($RegVal->"ssid") ] . "\n" . \ - [ $FormatLine "MAC" ($RegVal->"mac-address") ] . "\n" . \ - [ $FormatLine "Vendor" $Vendor ] . "\n" . \ - [ $FormatLine "Hostname" $HostName ] . "\n" . \ - [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ - [ $FormatLine "Date" $DateTime ]) }); - } - } else={ - $LogPrint debug $ScriptName ("No mac address available... Ignoring."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template new file mode 100644 index 0000000..1d031fe --- /dev/null +++ b/collect-wireless-mac.template @@ -0,0 +1,72 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac%TEMPL% +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# collect wireless mac adresses in access list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man' +# !! or 'interface wireless'! + +:global Identity; + +:global GetMacVendor; +:global LogPrintExit; +:global ScriptLock; +:global SendNotification; +:global SymbolForNotification; + +$ScriptLock "collect-wireless-mac%TEMPL%"; + +:if ([ :len [ / %PATH% access-list find where comment="--- collected above ---" disabled ] ] = 0) do={ + / %PATH% access-list add comment="--- collected above ---" disabled=yes; + $LogPrintExit warning "Added disabled access-list entry with comment '--- collected above ---'." false; +} +:local PlaceBefore ([ / %PATH% access-list find where comment="--- collected above ---" disabled ]->0); + +:foreach RegTbl in=[ / %PATH% registration-table find ] do={ + :local Mac [ / %PATH% registration-table get $RegTbl mac-address ]; + :local AccessList ([ / %PATH% access-list find where mac-address=$Mac ]->0); + :if ([ :len $AccessList ] = 0) do={ + :local Address "no dhcp lease"; + :local DnsName "no dhcp lease"; + :local HostName "no dhcp lease"; + :local Lease ([ / ip dhcp-server lease find where mac-address=$Mac dynamic=yes status=bound ]->0); + :if ([ :len $Lease ] > 0) do={ + :set Address [ / ip dhcp-server lease get $Lease address ]; + :set HostName [ / ip dhcp-server lease get $Lease host-name ]; + :if ([ :len $HostName ] = 0) do={ + :set HostName "no hostname"; + } + :set DnsName [ / ip dns static get ([ find where address=$Address ]->0) name ]; + :if ([ :len $DnsName ] = 0) do={ + :set DnsName "no dns name"; + } + } + :local RegEntry [ / %PATH% registration-table find where mac-address=$Mac ]; + :local Interface [ / %PATH% registration-table get $RegEntry interface ]; + :local Ssid [ / caps-man registration-table get $RegEntry ssid ]; + :local Ssid [ / interface wireless get [ find where name=$Interface ] ssid ]; + :local DateTime ([ / system clock get date ] . " " . [ / system clock get time ]); + :local Vendor [ $GetMacVendor $Mac ]; + :local Message ("unknown MAC address " . $Mac . " (" . $Vendor . ", " . $HostName . ") " . \ + "first seen on " . $DateTime . " connected to SSID " . $Ssid . ", interface " . $Interface); + $LogPrintExit info $Message false; + / %PATH% access-list add place-before=$PlaceBefore comment=$Message mac-address=$Mac disabled=yes; + $SendNotification ([ $SymbolForNotification "mobile-phone" ] . $Mac . " connected to " . $Ssid) \ + ("A device with unknown MAC address connected to " . $Ssid . " on " . $Identity . ".\n\n" . \ + "Controller: " . $Identity . "\n" . \ + "Interface: " . $Interface . "\n" . \ + "SSID: " . $Ssid . "\n" . \ + "MAC: " . $Mac . "\n" . \ + "Vendor: " . $Vendor . "\n" . \ + "Hostname: " . $HostName . "\n" . \ + "Address: " . $Address . "\n" . \ + "DNS name: " . $DnsName . "\n" . \ + "Date: " . $DateTime); + } else={ + $LogPrintExit debug ("MAC address " . $Mac . " already known: " . \ + [ / %PATH% access-list get $AccessList comment ]) false; + } +} diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc deleted file mode 100644 index da901be..0000000 --- a/collect-wireless-mac.template.rsc +++ /dev/null @@ -1,118 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=40 -# requires RouterOS, version=7.15 -# -# collect wireless mac adresses in access list -# https://rsc.eworm.de/doc/collect-wireless-mac.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - - :global EitherOr; - :global FormatLine; - :global FormatMultiLines; - :global GetMacVendor; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; - /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0); - :local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); - - :foreach Reg in=[ /caps-man/registration-table/find ] do={ - :foreach Reg in=[ /interface/wifi/registration-table/find ] do={ - :foreach Reg in=[ /interface/wireless/registration-table/find where ap=no ] do={ - :local RegVal; - :do { - :set RegVal [ /caps-man/registration-table/get $Reg ]; - :set RegVal [ /interface/wifi/registration-table/get $Reg ]; - :set RegVal [ /interface/wireless/registration-table/get $Reg ]; - } on-error={ - $LogPrint debug $ScriptName ("Device already gone... Ignoring."); - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]); - [ /interface/wifi/access-list/get $AccessList comment ]); - [ /interface/wireless/access-list/get $AccessList comment ]); - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease active-address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); - :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ - :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); - } - } - } - :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrint info $ScriptName $Message; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - /interface/wifi/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Controller" $Identity ] . "\n" . \ - [ $FormatLine "Interface" ($RegVal->"interface") ] . "\n" . \ - [ $FormatLine "SSID" ($RegVal->"ssid") ] . "\n" . \ - [ $FormatLine "MAC" ($RegVal->"mac-address") ] . "\n" . \ - [ $FormatLine "Vendor" $Vendor ] . "\n" . \ - [ $FormatLine "Hostname" $HostName ] . "\n" . \ - [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ - [ $FormatLine "Date" $DateTime ]) }); - } - } else={ - $LogPrint debug $ScriptName ("No mac address available... Ignoring."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc deleted file mode 100644 index cb217ce..0000000 --- a/collect-wireless-mac.wifi.rsc +++ /dev/null @@ -1,100 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.wifi -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=40 -# requires RouterOS, version=7.15 -# -# collect wireless mac adresses in access list -# https://rsc.eworm.de/doc/collect-wireless-mac.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - - :global EitherOr; - :global FormatLine; - :global FormatMultiLines; - :global GetMacVendor; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'."); - } - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0); - - :foreach Reg in=[ /interface/wifi/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /interface/wifi/registration-table/get $Reg ]; - } on-error={ - $LogPrint debug $ScriptName ("Device already gone... Ignoring."); - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wifi/access-list/get $AccessList comment ]); - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease active-address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); - :foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ - :set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); - } - } - } - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrint info $ScriptName $Message; - /interface/wifi/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - [ $FormatLine "Controller" $Identity ] . "\n" . \ - [ $FormatLine "Interface" ($RegVal->"interface") ] . "\n" . \ - [ $FormatLine "SSID" ($RegVal->"ssid") ] . "\n" . \ - [ $FormatLine "MAC" ($RegVal->"mac-address") ] . "\n" . \ - [ $FormatLine "Vendor" $Vendor ] . "\n" . \ - [ $FormatLine "Hostname" $HostName ] . "\n" . \ - [ $FormatLine "Address" $Address ] . "\n" . \ - [ $FormatMultiLines "DNS name" $DnsName ] . "\n" . \ - [ $FormatLine "Date" $DateTime ]) }); - } - } else={ - $LogPrint debug $ScriptName ("No mac address available... Ignoring."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/contrib/logo-color.d/browser-01.avif b/contrib/logo-color.d/browser-01.avif deleted file mode 100644 index 3dc0a1f..0000000 Binary files a/contrib/logo-color.d/browser-01.avif and /dev/null differ diff --git a/contrib/logo-color.d/browser-02.avif b/contrib/logo-color.d/browser-02.avif deleted file mode 100644 index 1867fbe..0000000 Binary files a/contrib/logo-color.d/browser-02.avif and /dev/null differ diff --git a/contrib/logo-color.d/browser-03.avif b/contrib/logo-color.d/browser-03.avif deleted file mode 100644 index dc24bbb..0000000 Binary files a/contrib/logo-color.d/browser-03.avif and /dev/null differ diff --git a/contrib/logo-color.d/script.js b/contrib/logo-color.d/script.js deleted file mode 100644 index 82cc204..0000000 --- a/contrib/logo-color.d/script.js +++ /dev/null @@ -1,12 +0,0 @@ -function invertHex(hex) { - return (Number("0x1" + hex) ^ 0xffffff).toString(16).substr(1); -} - -function color() { - var svg = document.querySelector(".logo").getSVGDocument(); - svg.getElementById("dark-1").setAttribute("stop-color", document.getElementById("color1").value); - svg.getElementById("dark-2").setAttribute("stop-color", document.getElementById("color2").value); - var background = document.getElementById("color3").value; - svg.getElementById("background").setAttribute("fill", background); - svg.getElementById("hexagon").setAttribute("stroke", "#" + invertHex(background.substring(1))); -} diff --git a/contrib/logo-color.d/style.css b/contrib/logo-color.d/style.css deleted file mode 100644 index eb2ec6a..0000000 --- a/contrib/logo-color.d/style.css +++ /dev/null @@ -1,5 +0,0 @@ -body { - font-family: fira-sans, sans-serif; - font-size: 10pt; - background-color: transparent; -} diff --git a/contrib/logo-color.html b/contrib/logo-color.html deleted file mode 100644 index 17942ce..0000000 --- a/contrib/logo-color.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - -RouterOS-Scripts Logo Color Changer - - - - - -

RouterOS-Scripts Logo Color Changer

- -

You want the logo for your own notifications? But you joined the -Telegram Group and want -something that differentiates? Color it!

- - - -

Select the colors here: - - -

- -

Then right-click, click "Take Screenshot" and finally select the -logo and download it.

- -

Screenshot Browser 01 -Screenshot Browser 02 -Screenshot Browser 03

- -

(This example is with -Firefox. The workflow -for other browsers may differ.)

- -

See how to -Set -a profile photo for your Telegram bot.

- - - diff --git a/contrib/notification.d/script.js b/contrib/notification.d/script.js deleted file mode 100644 index 91741fd..0000000 --- a/contrib/notification.d/script.js +++ /dev/null @@ -1,6 +0,0 @@ -function visible(cb, element) { - document.getElementById(element).style.display = cb.checked ? "block" : "none"; -} -function update(cb, element) { - document.getElementById(element).innerHTML = cb.value; -} diff --git a/contrib/notification.d/style.css b/contrib/notification.d/style.css deleted file mode 100644 index 648ea23..0000000 --- a/contrib/notification.d/style.css +++ /dev/null @@ -1,36 +0,0 @@ -body { - font-family: fira-sans, sans-serif; - font-size: 10pt; - background-color: transparent; -} -div.notification { - position: relative; - float: right; - width: 600px; - border: 3px outset #6c5d53; - /* border-radius: 5px; */ - padding: 10px; - background-color: #e6e6e6; -} -div.content { - padding-left: 60px; -} -img.logo { - float: left; - border-radius: 50%; -} -p.heading { - margin: 0px; - font-weight: bold; - text-decoration: underline; -} -p.hint { - display: none; -} -pre { - font-family: fira-mono, monospace; - white-space: pre-wrap; -} -span.link { - color: #863600; -} diff --git a/contrib/notification.html b/contrib/notification.html deleted file mode 100644 index 7875036..0000000 --- a/contrib/notification.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - -RouterOS-Scripts Notification Generator - - - - - -

RouterOS-Scripts Notification Generator

- -
- -
-

[MikroTik] ℹ️ Subject

-
Message
- -

⏰ This message was queued since oct/18/2022 18:30:48 and may be obsolete.

-

✂️ The message was too long and has been truncated, cut off 13%!

-
-
- -

Hostname:

-

Subject:

-

Message:

-

Show link:

-

Queued since

-

Cut-off with percent

- -

Then right-click, click "Take Screenshot" and finally select the -notification and download it.

- - - diff --git a/daily-psk.capsman b/daily-psk.capsman new file mode 100644 index 0000000..d7c4ad7 --- /dev/null +++ b/daily-psk.capsman @@ -0,0 +1,101 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.capsman +# Copyright (c) 2013-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:global DailyPskMatchComment; +:global Identity; + +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; + +# return pseudo-random string for PSK +:local GeneratePSK do={ + :local Date [ :tostr $1 ]; + + :global DailyPskSecrets; + + :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; + "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + + :local Month [ :pick $Date 0 3 ]; + :local Day [ :tonum [ :pick $Date 4 6 ] ]; + :local Year [ :pick $Date 7 11 ]; + + :for MIndex from=0 to=[ :len $Months ] do={ + :if ($Months->$MIndex = $Month) do={ + :set Month ($MIndex + 1); + } + } + + :local A ((14 - $Month) / 12); + :local B ($Year - $A); + :local C ($Month + 12 * $A - 2); + :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); + + :return (($DailyPskSecrets->0->($Day - 1)) . \ + ($DailyPskSecrets->1->($Month - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); +} + +:local Seen [ :toarray "" ]; +:local Date [ / system clock get date ]; +:local NewPsk [ $GeneratePSK $Date ]; + +:foreach AccList in=[ / caps-man access-list find where comment~$DailyPskMatchComment ] do={ + :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; + :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; + :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + / caps-man access-list set $AccList private-passphrase=$NewPsk; + + :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + + :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); + :local Attach "qrcode-daily.png"; + + :do { + / tool fetch check-certificate=yes-without-crl \ + $Url dst-path=$Attach; + $WaitForFile $Attach; + } on-error={ + :set Attach ""; + } + + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ + ("This is the daily PSK on " . $Identity . ":\n\n" . \ + "SSID: " . $Ssid . "\n" . \ + "PSK: " . $NewPsk . "\n" . \ + "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!") \ + $Url $Attach; + } + } + } +} diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc deleted file mode 100644 index 5672931..0000000 --- a/daily-psk.capsman.rsc +++ /dev/null @@ -1,96 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update daily PSK (pre shared key) -# https://rsc.eworm.de/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global DailyPskMatchComment; - :global DailyPskQrCodeUrl; - :global Identity; - - :global FormatLine; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - # return pseudo-random string for PSK - :local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :global ParseDate; - - :set Date [ $ParseDate $Date ]; - - :local A ((14 - ($Date->"month")) / 12); - :local B (($Date->"year") - $A); - :local C (($Date->"month") + 12 * $A - 2); - :local WeekDay (7000 + ($Date->"day") + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); - } - - :local Seen ({}); - :local Date [ /system/clock/get date ]; - :local NewPsk [ $GeneratePSK $Date ]; - - :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; - :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - - :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ($Seen->$Ssid = 1) do={ - $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); - } else={ - :local Link ($DailyPskQrCodeUrl . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ - [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - :set ($Seen->$Ssid) 1; - } - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/daily-psk.local b/daily-psk.local new file mode 100644 index 0000000..1add2e9 --- /dev/null +++ b/daily-psk.local @@ -0,0 +1,101 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.local +# Copyright (c) 2013-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! Do not edit this file, it is generated from template! + +:global DailyPskMatchComment; +:global Identity; + +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; + +# return pseudo-random string for PSK +:local GeneratePSK do={ + :local Date [ :tostr $1 ]; + + :global DailyPskSecrets; + + :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; + "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + + :local Month [ :pick $Date 0 3 ]; + :local Day [ :tonum [ :pick $Date 4 6 ] ]; + :local Year [ :pick $Date 7 11 ]; + + :for MIndex from=0 to=[ :len $Months ] do={ + :if ($Months->$MIndex = $Month) do={ + :set Month ($MIndex + 1); + } + } + + :local A ((14 - $Month) / 12); + :local B ($Year - $A); + :local C ($Month + 12 * $A - 2); + :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); + + :return (($DailyPskSecrets->0->($Day - 1)) . \ + ($DailyPskSecrets->1->($Month - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); +} + +:local Seen [ :toarray "" ]; +:local Date [ / system clock get date ]; +:local NewPsk [ $GeneratePSK $Date ]; + +:foreach AccList in=[ / interface wireless access-list find where comment~$DailyPskMatchComment ] do={ + :local IntName [ / interface wireless access-list get $AccList interface ]; + :local Ssid [ / interface wireless get $IntName ssid ]; + :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; + + :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + + :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); + :local Attach "qrcode-daily.png"; + + :do { + / tool fetch check-certificate=yes-without-crl \ + $Url dst-path=$Attach; + $WaitForFile $Attach; + } on-error={ + :set Attach ""; + } + + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ + ("This is the daily PSK on " . $Identity . ":\n\n" . \ + "SSID: " . $Ssid . "\n" . \ + "PSK: " . $NewPsk . "\n" . \ + "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!") \ + $Url $Attach; + } + } + } +} diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc deleted file mode 100644 index 9dea469..0000000 --- a/daily-psk.local.rsc +++ /dev/null @@ -1,95 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.local -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update daily PSK (pre shared key) -# https://rsc.eworm.de/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global DailyPskMatchComment; - :global DailyPskQrCodeUrl; - :global Identity; - - :global FormatLine; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - # return pseudo-random string for PSK - :local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :global ParseDate; - - :set Date [ $ParseDate $Date ]; - - :local A ((14 - ($Date->"month")) / 12); - :local B (($Date->"year") - $A); - :local C (($Date->"month") + 12 * $A - 2); - :local WeekDay (7000 + ($Date->"day") + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); - } - - :local Seen ({}); - :local Date [ /system/clock/get date ]; - :local NewPsk [ $GeneratePSK $Date ]; - - :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :if ($Seen->$Ssid = 1) do={ - $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); - } else={ - :local Link ($DailyPskQrCodeUrl . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ - [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - :set ($Seen->$Ssid) 1; - } - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/daily-psk.template b/daily-psk.template new file mode 100644 index 0000000..7f8cd75 --- /dev/null +++ b/daily-psk.template @@ -0,0 +1,107 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk%TEMPL% +# Copyright (c) 2013-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man' +# !! or 'interface wireless'! + +:global DailyPskMatchComment; +:global Identity; + +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; +:global UrlEncode; +:global WaitForFile; +:global WaitFullyConnected; + +$WaitFullyConnected; + +# return pseudo-random string for PSK +:local GeneratePSK do={ + :local Date [ :tostr $1 ]; + + :global DailyPskSecrets; + + :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; + "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; + + :local Month [ :pick $Date 0 3 ]; + :local Day [ :tonum [ :pick $Date 4 6 ] ]; + :local Year [ :pick $Date 7 11 ]; + + :for MIndex from=0 to=[ :len $Months ] do={ + :if ($Months->$MIndex = $Month) do={ + :set Month ($MIndex + 1); + } + } + + :local A ((14 - $Month) / 12); + :local B ($Year - $A); + :local C ($Month + 12 * $A - 2); + :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); + :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); + + :return (($DailyPskSecrets->0->($Day - 1)) . \ + ($DailyPskSecrets->1->($Month - 1)) . \ + ($DailyPskSecrets->2->$WeekDay)); +} + +:local Seen [ :toarray "" ]; +:local Date [ / system clock get date ]; +:local NewPsk [ $GeneratePSK $Date ]; + +:foreach AccList in=[ / %PATH% access-list find where comment~$DailyPskMatchComment ] do={ + :local IntName [ / interface wireless access-list get $AccList interface ]; + :local Ssid [ / interface wireless get $IntName ssid ]; + :local Ssid [ / caps-man access-list get $AccList ssid-regexp ]; + :local Configuration [ / caps-man configuration get ([ find where ssid=$Ssid ]->0) name ]; + :local OldPsk [ / interface wireless access-list get $AccList private-pre-shared-key ]; + :local OldPsk [ / caps-man access-list get $AccList private-passphrase ]; + :local Skip 0; + + :if ($NewPsk != $OldPsk) do={ + $LogPrintExit info ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; + / interface wireless access-list set $AccList private-pre-shared-key=$NewPsk; + / caps-man access-list set $AccList private-passphrase=$NewPsk; + + :if ([ :len [ / interface wireless find where name=$IntName disabled=no ] ] = 1) do={ + :if ([ :len [ / caps-man interface find where configuration=$Configuration ] ] > 0) do={ + :foreach SeenSsid in=$Seen do={ + :if ($SeenSsid = $Ssid) do={ + $LogPrintExit debug ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; + :set Skip 1; + } + } + + :if ($Skip = 0) do={ + :set Seen ($Seen, $Ssid); + + :local Url ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ + "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); + :local Attach "qrcode-daily.png"; + + :do { + / tool fetch check-certificate=yes-without-crl \ + $Url dst-path=$Attach; + $WaitForFile $Attach; + } on-error={ + :set Attach ""; + } + + $SendNotification ([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid) \ + ("This is the daily PSK on " . $Identity . ":\n\n" . \ + "SSID: " . $Ssid . "\n" . \ + "PSK: " . $NewPsk . "\n" . \ + "Date: " . $Date . "\n\n" . \ + "A client device specific rule must not exist!") \ + $Url $Attach; + } + } + } +} diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc deleted file mode 100644 index 8202eeb..0000000 --- a/daily-psk.template.rsc +++ /dev/null @@ -1,111 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update daily PSK (pre shared key) -# https://rsc.eworm.de/doc/daily-psk.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global DailyPskMatchComment; - :global DailyPskQrCodeUrl; - :global Identity; - - :global FormatLine; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - # return pseudo-random string for PSK - :local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :global ParseDate; - - :set Date [ $ParseDate $Date ]; - - :local A ((14 - ($Date->"month")) / 12); - :local B (($Date->"year") - $A); - :local C (($Date->"month") + 12 * $A - 2); - :local WeekDay (7000 + ($Date->"day") + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); - } - - :local Seen ({}); - :local Date [ /system/clock/get date ]; - :local NewPsk [ $GeneratePSK $Date ]; - - :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ - :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; - :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); - :local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /caps-man/configuration/get $Configuration ssid ]; - :local Ssid [ /interface/wifi/configuration/get $Configuration ssid ]; - :local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ]; - :local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ]; - # /caps-man/ /interface/wifi/ above - /interface/wireless/ below - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - - :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ([ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :if ($Seen->$Ssid = 1) do={ - $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); - } else={ - :local Link ($DailyPskQrCodeUrl . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ - [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - :set ($Seen->$Ssid) 1; - } - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc deleted file mode 100644 index 3de3c5b..0000000 --- a/daily-psk.wifi.rsc +++ /dev/null @@ -1,96 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.wifi -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update daily PSK (pre shared key) -# https://rsc.eworm.de/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global DailyPskMatchComment; - :global DailyPskQrCodeUrl; - :global Identity; - - :global FormatLine; - :global LogPrint; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global UrlEncode; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - # return pseudo-random string for PSK - :local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :global ParseDate; - - :set Date [ $ParseDate $Date ]; - - :local A ((14 - ($Date->"month")) / 12); - :local B (($Date->"year") - $A); - :local C (($Date->"month") + 12 * $A - 2); - :local WeekDay (7000 + ($Date->"day") + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \ - ($DailyPskSecrets->1->(($Date->"month") - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); - } - - :local Seen ({}); - :local Date [ /system/clock/get date ]; - :local NewPsk [ $GeneratePSK $Date ]; - - :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ - :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; - :local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); - :local Ssid [ /interface/wifi/configuration/get $Configuration ssid ]; - :local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrint info $ScriptName ("Updating daily PSK for '" . $Ssid . "' to '" . $NewPsk . "' (was '" . $OldPsk . "')"); - /interface/wifi/access-list/set $AccList passphrase=$NewPsk; - - :if ([ :len [ /interface/wifi/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ - :if ($Seen->$Ssid = 1) do={ - $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping."); - } else={ - :local Link ($DailyPskQrCodeUrl . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - [ $FormatLine "SSID" $Ssid 8 ] . "\n" . \ - [ $FormatLine "PSK" $NewPsk 8 ] . "\n" . \ - [ $FormatLine "Date" $Date 8 ] . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - :set ($Seen->$Ssid) 1; - } - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman new file mode 100644 index 0000000..b663a0a --- /dev/null +++ b/dhcp-lease-comment.capsman @@ -0,0 +1,24 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.capsman +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:global LogPrintExit; + +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local NewComment; + :local AccessList ([ / caps-man access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ / caps-man access-list get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + / ip dhcp-server lease set comment=$NewComment $Lease; + } +} diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc deleted file mode 100644 index 36b31c8..0000000 --- a/dhcp-lease-comment.capsman.rsc +++ /dev/null @@ -1,43 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=60 -# requires RouterOS, version=7.15 -# -# update dhcp-server lease comment with infos from access-list -# https://rsc.eworm.de/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /caps-man/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local new file mode 100644 index 0000000..1d9eb08 --- /dev/null +++ b/dhcp-lease-comment.local @@ -0,0 +1,24 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.local +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! Do not edit this file, it is generated from template! + +:global LogPrintExit; + +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local NewComment; + :local AccessList ([ / interface wireless access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ / interface wireless access-list get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + / ip dhcp-server lease set comment=$NewComment $Lease; + } +} diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc deleted file mode 100644 index 35dc6f6..0000000 --- a/dhcp-lease-comment.local.rsc +++ /dev/null @@ -1,43 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=60 -# requires RouterOS, version=7.15 -# -# update dhcp-server lease comment with infos from access-list -# https://rsc.eworm.de/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template new file mode 100644 index 0000000..4007765 --- /dev/null +++ b/dhcp-lease-comment.template @@ -0,0 +1,25 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment%TEMPL% +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update dhcp-server lease comment with infos from access-list +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md +# +# !! This is just a template! Replace '%PATH%' with 'caps-man' +# !! or 'interface wireless'! + +:global LogPrintExit; + +:foreach Lease in=[ / ip dhcp-server lease find where dynamic=yes status=bound ] do={ + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local NewComment; + :local AccessList ([ / %PATH% access-list find where mac-address=($LeaseVal->"mac-address") ]->0); + :if ([ :len $AccessList ] > 0) do={ + :set NewComment [ / %PATH% access-list get $AccessList comment ]; + } + :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ + $LogPrintExit info ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; + / ip dhcp-server lease set comment=$NewComment $Lease; + } +} diff --git a/dhcp-lease-comment.template.rsc b/dhcp-lease-comment.template.rsc deleted file mode 100644 index 47a8554..0000000 --- a/dhcp-lease-comment.template.rsc +++ /dev/null @@ -1,48 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=60 -# requires RouterOS, version=7.15 -# -# update dhcp-server lease comment with infos from access-list -# https://rsc.eworm.de/doc/dhcp-lease-comment.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /caps-man/access-list/get $AccessList comment ]; - :set NewComment [ /interface/wifi/access-list/get $AccessList comment ]; - :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc deleted file mode 100644 index e0f9785..0000000 --- a/dhcp-lease-comment.wifi.rsc +++ /dev/null @@ -1,43 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.wifi -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=60 -# requires RouterOS, version=7.15 -# -# update dhcp-server lease comment with infos from access-list -# https://rsc.eworm.de/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wifi/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wifi/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrint info $ScriptName ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment); - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/dhcp-to-dns b/dhcp-to-dns new file mode 100644 index 0000000..375e083 --- /dev/null +++ b/dhcp-to-dns @@ -0,0 +1,74 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-to-dns +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# check DHCP leases and add/remove/update DNS entries +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md + +:global Domain; +:global HostNameInZone; +:global Identity; +:global PrefixInZone; +:global ServerNameInZone; + +:global CharacterReplace; +:global IfThenElse; +:global LogPrintExit; + +:local Zone \ + ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ + [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); +:local Ttl 5m; +:local CommentPrefix "managed by dhcp-to-dns for "; + +:if ([ :len [ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ] ] = 0) do={ + / ip dns static add comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled=yes; + $LogPrintExit warning "Added disabled static dns record with comment '--- dhcp-to-dns above ---'." false; +} +:local PlaceBefore ([ / ip dns static find where comment="--- dhcp-to-dns above ---" name=- type=NXDOMAIN disabled ]->0); + +:foreach DnsRecord in=[ / ip dns static find where comment ~ $CommentPrefix ] do={ + :local DnsRecordVal [ / ip dns static get $DnsRecord ]; + :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; + :if ([ :len [ / ip dhcp-server lease find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ + $LogPrintExit debug ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; + } else={ + :local Found false; + $LogPrintExit info ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; + / ip dns static remove $DnsRecord; + } +} + +:foreach Lease in=[ / ip dhcp-server lease find where status=bound ] do={ + :local LeaseVal [ / ip dhcp-server lease get $Lease ]; + :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); + :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ + [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ + [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; + + :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); + :local DnsRecord [ / ip dns static find where name=$Fqdn ]; + :if ([ :len $DnsRecord ] > 0) do={ + :local DnsIp [ / ip dns static get $DnsRecord address ]; + + :local DupMacLeases [ / ip dhcp-server lease find where mac-address=($LeaseVal->"mac-address") status=bound ]; + :if ([ :len $DupMacLeases ] > 1) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; + } + + :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ + :set ($LeaseVal->"address") [ / ip dhcp-server lease get ([ find where host-name=($LeaseVal->"host-name") status=bound ]->0) address ]; + } + + :if ($DnsIp = $LeaseVal->"address") do={ + $LogPrintExit debug ("DNS entry for " . $Fqdn . " does not need updating.") false; + } else={ + $LogPrintExit info ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; + / ip dns static set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; + } + } else={ + $LogPrintExit info ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; + / ip dns static add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; + } +} diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc deleted file mode 100644 index 9b94098..0000000 --- a/dhcp-to-dns.rsc +++ /dev/null @@ -1,130 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=20 -# requires RouterOS, version=7.16 -# -# check DHCP leases and add/remove/update DNS entries -# https://rsc.eworm.de/doc/dhcp-to-dns.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Domain; - :global Identity; - - :global CleanName; - :global EitherOr; - :global IfThenElse; - :global LogPrint; - :global LogPrintOnce; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :local Ttl 5m; - :local CommentPrefix ("managed by " . $ScriptName); - :local CommentString ("--- " . $ScriptName . " above ---"); - - :if ([ :len [ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add name=$CommentString type=NXDOMAIN disabled=yes; - $LogPrint warning $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'."); - } - :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); - - :foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix . "\\b") type=A ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local DnsRecordInfo [ $ParseKeyValueStore ($DnsRecordVal->"comment") ]; - :local MacInServer ($DnsRecordInfo->"macaddress" . " in " . $DnsRecordInfo->"server"); - - :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=($DnsRecordInfo->"macaddress") \ - active-address=($DnsRecordVal->"address") server=($DnsRecordInfo->"server") status=bound ] ] > 0) do={ - $LogPrint debug $ScriptName ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record."); - } else={ - :local Found false; - $LogPrint info $ScriptName ("Lease expired for " . $MacInServer . ", deleting record (" . $DnsRecordVal->"name" . ")."); - /ip/dns/static/remove $DnsRecord; - /ip/dns/static/remove [ find where type=CNAME comment=($DnsRecordVal->"comment") ]; - } - } - - :foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ - :local LeaseVal; - :do { - :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ] ] > 1) do={ - $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!"); - } - } on-error={ - $LogPrint debug $ScriptName ("A lease just vanished, ignoring."); - } - - :if ([ :len ($LeaseVal->"active-address") ] > 0) do={ - :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); - :local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ]; - :local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ]; - :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; - :local NetworkVal; - :if ([ :len $Network ] > 0) do={ - :set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; - } - :local NetworkInfo [ $ParseKeyValueStore ($NetworkVal->"comment") ]; - :local NetDomain ([ $IfThenElse ([ :len ($NetworkInfo->"name-extra") ] > 0) ($NetworkInfo->"name-extra" . ".") ] . \ - [ $EitherOr [ $EitherOr ($NetworkInfo->"domain") ($NetworkVal->"domain") ] $Domain ]); - :local FullA ($MacDash . "." . $NetDomain); - :local FullCN ($HostName . "." . $NetDomain); - :local MacInServer ($LeaseVal->"active-mac-address" . " in " . $LeaseVal->"server"); - - :local DnsRecord [ /ip/dns/static/find where comment=$Comment type=A ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - - :if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ - $LogPrint debug $ScriptName ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating."); - } else={ - $LogPrint info $ScriptName ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ")."); - /ip/dns/static/set address=($LeaseVal->"active-address") name=$FullA $DnsRecord; - } - - :local CName [ /ip/dns/static/find where comment=$Comment type=CNAME ]; - :if ([ :len $CName ] > 0) do={ - :local CNameVal [ /ip/dns/static/get $CName ]; - :if ($CNameVal->"name" != $FullCN || $CNameVal->"cname" != $FullA) do={ - $LogPrint info $ScriptName ("Deleting CNAME record with wrong data for " . $MacInServer . "."); - /ip/dns/static/remove $CName; - } - } - :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={ - $LogPrint info $ScriptName ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ")."); - /ip/dns/static/add name=$FullCN type=CNAME cname=$FullA ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } - - } else={ - $LogPrint info $ScriptName ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ")."); - /ip/dns/static/add name=$FullA type=A address=($LeaseVal->"active-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - :if ([ :len $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={ - $LogPrint info $ScriptName ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ")."); - /ip/dns/static/add name=$FullCN type=CNAME cname=$FullA ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } - } - - :if ([ :len [ /ip/dns/static/find where name=$FullA type=A ] ] > 1) do={ - $LogPrintOnce warning $ScriptName ("The name '" . $FullA . "' appeared in more than one A record!"); - } - } else={ - $LogPrint debug $ScriptName ("No address available... Ignoring."); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/doc/accesslist-duplicates.d/01-example.avif b/doc/accesslist-duplicates.d/01-example.avif deleted file mode 100644 index 11b3fc5..0000000 Binary files a/doc/accesslist-duplicates.d/01-example.avif and /dev/null differ diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index e4d0c7f..2189322 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -1,17 +1,7 @@ Find and remove access list duplicates ====================================== -[![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) - -> ℹ️️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -22,19 +12,14 @@ entries in wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), legacy -wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. -For `wifi`: - - $ScriptInstallUpdate accesslist-duplicates.wifi; - -For legacy CAPsMAN: +For CAPsMAN: $ScriptInstallUpdate accesslist-duplicates.capsman; -For legacy local interface: +For local interface: $ScriptInstallUpdate accesslist-duplicates.local; @@ -43,9 +28,16 @@ Usage and invocation Run this script from a terminal: - /system/script/run accesslist-duplicates.wifi; + [admin@kalyke] > / system script run accesslist-duplicates.local + Flags: X - disabled + 0 ;;; First entry with identical mac address... + mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 -![screenshot: example](accesslist-duplicates.d/01-example.avif) + 1 ;;; Second entry with identical mac address... + mac-address=00:11:22:33:44:55 interface=any signal-range=-120..120 allow-signal-out-of-range=10s authentication=yes forwarding=yes ap-tx-limit=0 client-tx-limit=0 private-algo=none private-key="" private-pre-shared-key="" management-protection-key="" vlan-mode=default vlan-id=1 + + Numeric id to remove, any key to skip! + Removing numeric id 1... See also -------- @@ -53,5 +45,5 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/backup-cloud.d/notification.avif b/doc/backup-cloud.d/notification.avif deleted file mode 100644 index e533908..0000000 Binary files a/doc/backup-cloud.d/notification.avif and /dev/null differ diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md deleted file mode 100644 index 7286960..0000000 --- a/doc/backup-cloud.md +++ /dev/null @@ -1,76 +0,0 @@ -Upload backup to Mikrotik cloud -=============================== - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script uploads -[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 -> workaround only. A notification *should* be sent anyway. But it can result -> in malfunction of fetch command (where all up- and downloads break) for -> some time. Failed notifications are queued then. - -### Sample notification - -![backup-cloud notification](backup-cloud.d/notification.avif) - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate backup-cloud; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler - -> ℹ️ **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. - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). - -Usage and invocation --------------------- - -Just run the script: - - /system/script/run backup-cloud; - -Creating a scheduler may be an option: - - /system/scheduler/add interval=1w name=backup-cloud on-event="/system/script/run backup-cloud;" start-time=09:20:00; - -See also --------- - -* [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](backup-partition.md) -* [Upload backup to server](backup-upload.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/backup-email.md b/doc/backup-email.md deleted file mode 100644 index 7b8bcfe..0000000 --- a/doc/backup-email.md +++ /dev/null @@ -1,68 +0,0 @@ -Send backup via e-mail -====================== - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script sends binary backup (`/system/backup/save`) and complete -configuration export (`/export terse show-sensitive`) via e-mail. - -Requirements and installation ------------------------------ - -Just install the script and the required module: - - $ScriptInstallUpdate mod/notification-email,backup-email; - -Also make sure you configure -[sending notifications via e-mail](mod/notification-email.md). - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupSendBinary`: whether to send binary backup -* `BackupSendExport`: whether to send configuration export -* `BackupSendGlobalConfig`: whether to send `global-config-overlay` -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler - -> ℹ️ **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. - -Usage and invocation --------------------- - -Just run the script: - - /system/script/run backup-email; - -Creating a scheduler may be an option: - - /system/scheduler/add interval=1w name=backup-email on-event="/system/script/run backup-email;" start-time=09:15:00; - -See also --------- - -* [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Save configuration to fallback partition](backup-partition.md) -* [Send notifications via e-mail](mod/notification-email.md) -* [Upload backup to server](backup-upload.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/backup-partition.md b/doc/backup-partition.md deleted file mode 100644 index 9d615a5..0000000 --- a/doc/backup-partition.md +++ /dev/null @@ -1,78 +0,0 @@ -Save configuration to fallback partition -======================================== - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script saves the current configuration to fallback -[partition](https://wiki.mikrotik.com/wiki/Manual:Partitions). -It can also copy-over the RouterOS installation when run interactively -or just before a feature update. - -For this to work you need a device with sufficient flash storage that is -properly partitioned. - -To make you aware of a possible issue a scheduler logging a warning is -added in the backup partition's configuration. You may want to use -[log-forward](log-forward.md) to be notified. - -> ⚠️ **Warning**: By default only the configuration is saved to backup -> partition. Every now and then you should copy your installation over -> for a recent RouterOS version! See below for options. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate backup-partition; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, the only parameter is: - -* `BackupPartitionCopyBeforeFeatureUpdate`: copy-over the RouterOS - installation when a feature update is pending - -> ℹ️ **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. - -Usage and invocation --------------------- - -Just run the script: - - /system/script/run backup-partition; - -When run interactively from terminal it supports to copy-over the RouterOS -installation when versions differ. - -Creating a scheduler may be an option: - - /system/scheduler/add interval=1w name=backup-partition on-event="/system/script/run backup-partition;" start-time=09:30:00; - -See also --------- - -* [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Send backup via e-mail](backup-email.md) -* [Upload backup to server](backup-upload.md) -* [Forward log messages via notification](log-forward.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/backup-upload.d/notification.avif b/doc/backup-upload.d/notification.avif deleted file mode 100644 index 83cfb18..0000000 Binary files a/doc/backup-upload.d/notification.avif and /dev/null differ diff --git a/doc/backup-upload.md b/doc/backup-upload.md deleted file mode 100644 index 6a5b0e4..0000000 --- a/doc/backup-upload.md +++ /dev/null @@ -1,92 +0,0 @@ -Upload backup to server -======================= - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script uploads binary backup (`/system/backup/save`) and complete -configuration export (`/export terse show-sensitive`) to external server. - -> ⚠️ **Warning**: The used command can hit errors that a script can not handle. -> This may result in script termination (where no notification is sent) or -> malfunction of fetch command (where all up- and downloads break) for some -> time. Failed notifications are queued then. - -### Sample notification - -![backup-upload notification](backup-upload.d/notification.avif) - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate backup-upload; - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `BackupSendBinary`: whether to send binary backup -* `BackupSendExport`: whether to send configuration export -* `BackupSendGlobalConfig`: whether to send `global-config-overlay` -* `BackupPassword`: password to encrypt the backup with -* `BackupRandomDelay`: delay up to amount of seconds when run from scheduler -* `BackupUploadUrl`: url to upload to -* `BackupUploadUser`: username for server authentication -* `BackupUploadPass`: password for server authentication - -> ℹ️ **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. - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). - -### Issues with SFTP client - -The RouterOS SFTP client is picky if it comes to authentication methods. -I had to disable all but password authentication on server side. For openssh -edit `/etc/ssh/sshd_config` and add a directive like this, changed for your -needs: - - Match User mikrotik - AuthenticationMethods password - -Usage and invocation --------------------- - -Just run the script: - - /system/script/run backup-upload; - -Creating a scheduler may be an option: - - /system/scheduler/add interval=1w name=backup-upload on-event="/system/script/run backup-upload;" start-time=09:25:00; - -See also --------- - -* [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](backup-partition.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/bridge-port.md b/doc/bridge-port.md new file mode 100644 index 0000000..167fa87 --- /dev/null +++ b/doc/bridge-port.md @@ -0,0 +1,85 @@ +Manage ports in bridge +====================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +These scripts are supposed to handle interfaces and switching them from +one bridge to another. + +Requirements and installation +----------------------------- + +Just install the scripts: + + $ScriptInstallUpdate bridge-port-to-default,bridge-port-toggle; + +Configuration +------------- + +The configuration goes to ports' comments (`/ interface bridge port`). + + / interface bridge port add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; + / interface bridge port add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; + / interface bridge port add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; + +Also dhcp client can be handled: + + / ip dhcp-client add comment="toggle with bridge port" disabled=no interface=en1; + +There is also global configuration: + +* `BridgePortTo`: specify the configuration to be applied by default + +Install [global-wait](global-wait.md) and add a scheduler to start with +default setup on system startup: + + $ScriptInstallUpdate global-wait; + / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; + +Usage and invocation +-------------------- + +The usage examples show what happens with the configuration from above. + +Running the script `bridge-port-to-default` applies all configuration given +with `default=`: + + / system script run bridge-port-to-default; + +For the three interfaces we get this configuration: + +* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. +* Interface `en2` is put in bridge `br-intern`. +* Interface `en3` is put in bridge `br-guest`. + +Running the script `bridge-port-toggle` toggles to configuration given +with `alt=`: + + / system script run bridge-port-toggle; + +* Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. +* Interface `en2` is put in bridge `br-guest`. +* Interface `en3` is unchanged, stays in bridge `br-guest`. + +Running the script `bridge-port-toggle` again toggles back to configuration +given with `default=`. + +More configuration can be loaded by setting `BridgePortTo`: + + :set BridgePortTo "extra"; + / system script run bridge-port-to-default; + +* Interfaces `en1` and `en2` are unchanged. +* Interface `en3` is put in bridge `br-intern`. + +See also +-------- + +* [Wait for configuration und functions](global-wait.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 5722227..5acf914 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -1,17 +1,7 @@ Download packages for CAP upgrade from CAPsMAN ============================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -25,47 +15,35 @@ This script automatically downloads these packages. Requirements and installation ----------------------------- -Make sure you have the `package-path` set in your CAPsMAN configuration, -as that is where packages are downloaded to and where the system expects -them. +Just install the script on CAPsMAN device: -Then just install the script on CAPsMAN device. -Depending on whether you use `wifi` package (`/interface/wifi`) or legacy -wifi with CAPsMAN (`/caps-man`) you need to install a different script. + $ScriptInstallUpdate capsman-download-packages; -For `wifi`: +Optionally install [global-wait](global-wait.md) and add a scheduler to run +after startup: - $ScriptInstallUpdate capsman-download-packages.wifi; + $ScriptInstallUpdate global-wait; + / system scheduler add name=capsman-download-packages on-event="/ system script { run global-wait; run capsman-download-packages; }" start-time=startup; -For legacy CAPsMAN: +Only packages available in older version are downloaded. For initial setup +place the required packages to CAPsMAN package path (see +`/ caps-man manager`). The packages can be downloaded from device with +function `$DownloadPackage`, use something like this to download latest +packages to directory `routeros`: - $ScriptInstallUpdate capsman-download-packages.capsman; - -Optionally add a scheduler to run after startup. For `wifi`: - - /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifi;" start-time=startup; - -For legacy CAPsMAN: - - /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup; - -Packages available in local storage in older version are downloaded -unconditionally. - -If no packages are found the script downloads a default set of packages: - - * `wifi`: `routeros` and `wifi-qcom` for *arm* and *arm64*, `wifi-qcom-ac` for *arm* - * legacy CAPsMAN: `routeros` and `wireless` for *arm* and *mipsbe* - -> ℹ️ **Info**: If you have packages in the directory and things go wrong for -> what ever unknown reason: Remove **all** packages and start over. + $DownloadPackage system "" arm routeros; + $DownloadPackage security "" arm routeros; + [...] + $DownloadPackage system "" mipsbe routeros; + $DownloadPackage security "" mipsbe routeros; + [...] Usage and invocation -------------------- Run the script manually: - /system/script/run capsman-download-packages.wifi; + / system script run capsman-download-packages; ... or from scheduler. @@ -77,7 +55,8 @@ See also -------- * [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-upgrade.md) +* [Wait for configuration und functions](global-wait.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index d277db6..04952e2 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -1,17 +1,7 @@ Run rolling CAP upgrades from CAPsMAN ===================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -27,17 +17,9 @@ parallel. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device. -Depending on whether you use `wifi` package (`/interface/wifi`) or legacy -wifi with CAPsMAN (`/caps-man`) you need to install a different script. +Just install the script: -For `wifi`: - - $ScriptInstallUpdate capsman-rolling-upgrade.wifi; - -For legacy CAPsMAN: - - $ScriptInstallUpdate capsman-rolling-upgrade.capsman; + $ScriptInstallUpdate capsman-rolling-upgrade; Usage and invocation -------------------- @@ -48,7 +30,7 @@ that script when required. Alternatively run it manually: - /system/script/run capsman-rolling-upgrade.wifi; + / system script run capsman-rolling-upgrade; See also -------- @@ -56,5 +38,5 @@ See also * [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/certificate-renew-issued.md b/doc/certificate-renew-issued.md index c4615b5..e460ce1 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -1,17 +1,7 @@ Renew locally issued certificates ================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -35,16 +25,12 @@ parameter: * `CertRenewPass`: an array holding individual passphrases for certificates -> ℹ️ **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. - Usage and invocation -------------------- Run the script to renew certificates issued from a local CA. - /system/script/run certificate-renew-issued; + / system script run certificate-renew-issued; Only scripts with a remaining lifetime of three weeks or less are renewed. The old certificate is revoked automatically. If a passphrase for a specific @@ -57,5 +43,5 @@ See also * [Renew certificates and notify on expiration](check-certificates.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/check-certificates.d/notification.avif b/doc/check-certificates.d/notification.avif deleted file mode 100644 index 7c250da..0000000 Binary files a/doc/check-certificates.d/notification.avif and /dev/null differ diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 4c144ba..6e4a851 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -1,17 +1,7 @@ Renew certificates and notify on expiration =========================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -19,10 +9,6 @@ Description This script tries to download and renew certificates, then notifies about certificates that are still about to expire. -### Sample notification - -![check-certificates notification](check-certificates.d/notification.avif) - Requirements and installation ----------------------------- @@ -33,59 +19,32 @@ Just install the script: Configuration ------------- +The expiry notifications just require notification settings for e-mail and +telegram. + For automatic download and renewal of certificates you need configuration in `global-config-overlay`, these are the parameters: * `CertRenewPass`: an array of passphrases to try -* `CertRenewTime`: on what remaining time to try a renew * `CertRenewUrl`: the url to download certificates from -* `CertWarnTime`: on what remaining time to warn via notification -> ℹ️ **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. - -Certificates on the web server should be named by their common name, like -`CN.pem` (`PEM` format) or`CN.p12` (`PKCS#12` format). Alternatively any -subject alternative name (aka *Subject Alt Name* or *SAN*) can be used. - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). +Certificates on the web server should be named `CN.pem` (`PEM` format) or +`CN.p12` (`PKCS#12` format). Usage and invocation -------------------- Just run the script: - /system/script/run check-certificates; + / system script run check-certificates; ... or create a scheduler for periodic execution: - /system/scheduler/add interval=1d name=check-certificates on-event="/system/script/run check-certificates;" start-time=startup; + / system scheduler add interval=1d name=check-certificates on-event="/ system script run check-certificates;" start-time=startup; +Alternatively running on startup may be desired: -Tips & Tricks -------------- - -### Schedule at startup - -The script checks for full connectivity before acting, so scheduling at -startup is perfectly valid: - - /system/scheduler/add name=check-certificates@startup on-event="/system/script/run check-certificates;" start-time=startup; - -### Initial import - -Given you have a certificate on you server, you can use `check-certificates` -for the initial import. Just create a *dummy* certificate with short lifetime -that matches criteria to be renewed: - - /certificate/add name=example.com common-name=example.com days-valid=1; - /certificate/sign example.com; - /system/script/run check-certificates; + / system scheduler add name=check-certificates-startup on-event="/ system script { run global-wait; run check-certificates; }" start-time=startup; See also -------- @@ -93,5 +52,5 @@ See also * [Renew locally issued certificates](certificate-renew-issued.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/check-health.d/notification-01-cpu-utilization-high.avif b/doc/check-health.d/notification-01-cpu-utilization-high.avif deleted file mode 100644 index 326e7fe..0000000 Binary files a/doc/check-health.d/notification-01-cpu-utilization-high.avif and /dev/null differ diff --git a/doc/check-health.d/notification-02-cpu-utilization-ok.avif b/doc/check-health.d/notification-02-cpu-utilization-ok.avif deleted file mode 100644 index 811ccd7..0000000 Binary files a/doc/check-health.d/notification-02-cpu-utilization-ok.avif and /dev/null differ diff --git a/doc/check-health.d/notification-03-ram-utilization-high.avif b/doc/check-health.d/notification-03-ram-utilization-high.avif deleted file mode 100644 index 59155c5..0000000 Binary files a/doc/check-health.d/notification-03-ram-utilization-high.avif and /dev/null differ diff --git a/doc/check-health.d/notification-04-ram-utilization-ok.avif b/doc/check-health.d/notification-04-ram-utilization-ok.avif deleted file mode 100644 index d995b9a..0000000 Binary files a/doc/check-health.d/notification-04-ram-utilization-ok.avif and /dev/null differ diff --git a/doc/check-health.d/notification-05-voltage.avif b/doc/check-health.d/notification-05-voltage.avif deleted file mode 100644 index 17a385b..0000000 Binary files a/doc/check-health.d/notification-05-voltage.avif and /dev/null differ diff --git a/doc/check-health.d/notification-06-temperature-high.avif b/doc/check-health.d/notification-06-temperature-high.avif deleted file mode 100644 index 60d3802..0000000 Binary files a/doc/check-health.d/notification-06-temperature-high.avif and /dev/null differ diff --git a/doc/check-health.d/notification-07-temperature-ok.avif b/doc/check-health.d/notification-07-temperature-ok.avif deleted file mode 100644 index 4afed02..0000000 Binary files a/doc/check-health.d/notification-07-temperature-ok.avif and /dev/null differ diff --git a/doc/check-health.d/notification-08-state-fail.avif b/doc/check-health.d/notification-08-state-fail.avif deleted file mode 100644 index ad049ac..0000000 Binary files a/doc/check-health.d/notification-08-state-fail.avif and /dev/null differ diff --git a/doc/check-health.d/notification-09-state-ok.avif b/doc/check-health.d/notification-09-state-ok.avif deleted file mode 100644 index 26f5a74..0000000 Binary files a/doc/check-health.d/notification-09-state-ok.avif and /dev/null differ diff --git a/doc/check-health.md b/doc/check-health.md index 7cf0c33..37f8e34 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -1,66 +1,24 @@ Notify about health state ========================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- This script is run from scheduler periodically, sending notification on -health related events. Monitoring CPU and RAM utilization (available -processing and memory resources) works on all devices: - -* high CPU utilization -* high RAM utilization (low available RAM) - -With additional plugins functionality can be extended, depending on -sensors available in hardware: +health related events: * voltage jumps up or down more than configured threshold -* voltage drops below hard lower limit -* fan failed or recovered * power supply failed or recovered * temperature is above or below threshold -> ⚠️ **Warning**: Note that bad initial state will not trigger an event! For -> example rebooting a device that is already too hot will not trigger an -> alert on high temperature. +Note that bad initial state will not trigger an event. -### Sample notifications +Only sensors available in hardware can be checked. See what your +hardware supports: -#### CPU utilization - -![check-health notification cpu utilization high](check-health.d/notification-01-cpu-utilization-high.avif) -![check-health notification cpu utilization ok](check-health.d/notification-02-cpu-utilization-ok.avif) - -#### RAM utilization (low available RAM) - -![check-health notification ram utilization high](check-health.d/notification-03-ram-utilization-high.avif) -![check-health notification ram utilization ok](check-health.d/notification-04-ram-utilization-ok.avif) - -#### Voltage - -![check-health notification voltage](check-health.d/notification-05-voltage.avif) - -#### Temperature - -![check-health notification temperature high](check-health.d/notification-06-temperature-high.avif) -![check-health notification temperature ok](check-health.d/notification-07-temperature-ok.avif) - -#### PSU state - -![check-health notification state fail](check-health.d/notification-08-state-fail.avif) -![check-health notification state ok](check-health.d/notification-09-state-ok.avif) + / system health print; Requirements and installation ----------------------------- @@ -68,55 +26,18 @@ Requirements and installation Just install the script and create a scheduler: $ScriptInstallUpdate check-health; - /system/scheduler/add interval=53s name=check-health on-event="/system/script/run check-health;" start-time=startup; - -> ℹ️ **Info**: Running lots of scripts simultaneously can tamper the -> precision of cpu utilization, escpecially on devices with limited -> resources. Thus an unusual interval is used here. - -### Plugins - -Additional plugins are available for sensors available in hardware. First -check what your hardware supports: - - /system/health/print; - -Then install the plugin for *fan* and *power supply unit* *state*: - - $ScriptInstallUpdate check-health,check-health.d/state; - -... or *temperature*: - - $ScriptInstallUpdate check-health,check-health.d/temperature; - -... or *voltage*: - - $ScriptInstallUpdate check-health,check-health.d/voltage; - -You can also combine the commands and install all or a subset of plugins -in one go: - - $ScriptInstallUpdate check-health,check-health.d/state,check-health.d/temperature,check-health.d/voltage; + / system scheduler add interval=1m name=check-health on-event="/ system script run check-health;" start-time=startup; Configuration ------------- -The configuration goes to `global-config-overlay`, these are the parameters: +The configuration goes to `global-config-overlay`, These are the parameters: * `CheckHealthTemperature`: an array specifying temperature thresholds for sensors -* `CheckHealthVoltageLow`: value (in volt*10) giving a hard lower limit * `CheckHealthVoltagePercent`: percentage value to trigger voltage jumps -> ℹ️ **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. - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). +Also notification settings are required for e-mail and telegram. --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/check-lte-firmware-upgrade.d/notification.avif b/doc/check-lte-firmware-upgrade.d/notification.avif deleted file mode 100644 index c440da5..0000000 Binary files a/doc/check-lte-firmware-upgrade.d/notification.avif and /dev/null differ diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index 3693b71..c71dee5 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -1,17 +1,7 @@ Notify on LTE firmware upgrade ============================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -24,10 +14,6 @@ upgrades. Currently supported LTE hardware: * R11e-4G * R11e-LTE6 -### Sample notification - -![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.avif) - Requirements and installation ----------------------------- @@ -37,15 +23,12 @@ Just install the script: ... and create a scheduler: - /system/scheduler/add interval=1d name=check-lte-firmware-upgrade on-event="/system/script/run check-lte-firmware-upgrade;" start-time=startup; + / system scheduler add interval=1d name=check-lte-firmware-upgrade on-event="/ system script run check-lte-firmware-upgrade;" start-time=startup; Configuration ------------- -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md). +Notification setting are required for e-mail and telegram. See also -------- @@ -54,5 +37,5 @@ See also * [Install LTE firmware upgrade](unattended-lte-firmware-upgrade.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/check-routeros-update.d/notification.avif b/doc/check-routeros-update.d/notification.avif deleted file mode 100644 index 50317cf..0000000 Binary files a/doc/check-routeros-update.d/notification.avif and /dev/null differ diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index 926b4aa..bd25ab1 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -1,17 +1,7 @@ Notify on RouterOS update ========================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -21,24 +11,11 @@ The primary use of this script is to notify about RouterOS updates. Run from a terminal you can start the update process or schedule it. Centrally managing update process of several devices is possibly by -specifying versions safe to be updated on a web server. Versions seen -in neighbor discovery can be specified to be safe as well. +specifying versions safe to be updated on a web server. Also installing patch updates (where just last digit is increased) automatically is supported. -> ⚠️ **Warning**: Installing updates is important from a security point -> of view. At the same time it can be source of serve breakage. So test -> versions in lab and read -> [changelog](https://mikrotik.com/download/changelogs/) and -> [forum](https://forum.mikrotik.com/viewforum.php?f=21) before deploying -> to your production environment! Automatic updates should be handled -> with care! - -### Sample notification - -![check-routeros-update notification](check-routeros-update.d/notification.avif) - Requirements and installation ----------------------------- @@ -48,60 +25,36 @@ Just install the script: And add a scheduler for automatic update notification: - /system/scheduler/add interval=1d name=check-routeros-update on-event="/system/script/run check-routeros-update;" start-time=startup; + / system scheduler add interval=1d name=check-routeros-update on-event="/ system script run check-routeros-update;" start-time=startup; Configuration ------------- -No extra configuration is required to receive notifications. Several -mechanisms are availalbe to enable automatic installation of updates. -The configuration goes to `global-config-overlay`, these are the parameters: +Configuration is required only if you want to control update process with +safe versions from a web server. The configuration goes to +`global-config-overlay`, this is the parameter: -* `SafeUpdateNeighbor`: install updates automatically if at least one other - device is seen in neighbor list with new version -* `SafeUpdateNeighborIdentity`: regular expression to match identity for - trusted devices, leave empty to match all -* `SafeUpdatePatch`: install patch updates (where just last digit changes) - automatically -* `SafeUpdateUrl`: url on webserver to check for safe update, the channel - (`long-term`, `stable` or `testing`) is appended -* `SafeUpdateAll`: install **all** updates automatically - -> ℹ️ **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. - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). +* `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list +* `SafeUpdatePatch`: install patch updates automatically +* `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, +`stable` or `testing`) is appended Usage and invocation -------------------- Be notified when run from scheduler or run it manually: - /system/script/run check-routeros-update; + / system script run check-routeros-update; If an update is found you can install it right away. Installing script [packages-update](packages-update.md) gives extra options. -Tips & Tricks -------------- - -The script checks for full connectivity before acting, so scheduling at -startup is perfectly valid: - - /system/scheduler/add name=check-routeros-update@startup on-event="/system/script/run check-routeros-update;" start-time=startup; - See also -------- -* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) * [Manage system update](packages-update.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/cloud-backup.md b/doc/cloud-backup.md index e161cfa..bda1267 100644 --- a/doc/cloud-backup.md +++ b/doc/cloud-backup.md @@ -1 +1,46 @@ -This script has been renamed. Please see [backup-cloud](backup-cloud.md). +Upload backup to Mikrotik cloud +=============================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script uploads [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate cloud-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the only parameter: + +* `BackupPassword`: password to encrypt the backup with + +Also notification settings are required for e-mail and telegram. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run cloud-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=cloud-backup on-event="/ system script run cloud-backup;" start-time=09:20:00; + +See also +-------- + +* [Send backup via e-mail](email-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/collect-wireless-mac.d/notification.avif b/doc/collect-wireless-mac.d/notification.avif deleted file mode 100644 index a2833f0..0000000 Binary files a/doc/collect-wireless-mac.d/notification.avif and /dev/null differ diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index 0197522..45489bf 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -1,17 +1,7 @@ Collect MAC addresses in wireless access list ============================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -22,26 +12,17 @@ address list. In addition a notification is sent. By default the access list entry is disabled, but you can easily enable and modify it to your needs. -### Sample notification - -![collect-wireless-mac notification](collect-wireless-mac.d/notification.avif) - Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), legacy -wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. -For `wifi`: - - $ScriptInstallUpdate collect-wireless-mac.wifi; - -For legacy CAPsMAN: +For CAPsMAN: $ScriptInstallUpdate collect-wireless-mac.capsman; -For legacy local interface: +For local interface: $ScriptInstallUpdate collect-wireless-mac.local; @@ -52,11 +33,7 @@ On first run a disabled access list entry acting as marker (with comment "`--- collected above ---`") is added. Move this entry to define where new entries are to be added. -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). +Also notification settings are required for e-mail and telegram. Usage and invocation -------------------- @@ -73,5 +50,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/daily-psk.d/notification.avif b/doc/daily-psk.d/notification.avif deleted file mode 100644 index dd0b1b6..0000000 Binary files a/doc/daily-psk.d/notification.avif and /dev/null differ diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 4a3de64..c6055d6 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -1,17 +1,7 @@ Use wireless network with daily psk =================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -19,37 +9,26 @@ Description This script is supposed to provide a wifi network which changes the passphrase to a pseudo-random string daily. -### Sample notification - -![daily-psk notification](daily-psk.d/notification.avif) - Requirements and installation ----------------------------- -Just install this script. +Just install this script and [global-wait](global-wait.md). -Depending on whether you use `wifi` package (`/interface/wifi`), legacy -wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script and add -schedulers to run the script: +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. -For `wifi`: +For CAPsMAN: - $ScriptInstallUpdate daily-psk.wifi; - /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.wifi;" start-time=03:00:00; - /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.wifi;" start-time=startup; + $ScriptInstallUpdate daily-psk.capsman,global-wait; -For legacy CAPsMAN: +For local interface: - $ScriptInstallUpdate daily-psk.capsman; - /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.capsman;" start-time=03:00:00; - /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.capsman;" start-time=startup; + $ScriptInstallUpdate daily-psk.local,global-wait; -For legacy local interface: +And add schedulers to run the script: - $ScriptInstallUpdate daily-psk.local; - /system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.local;" start-time=03:00:00; - /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.local;" start-time=startup; + / system scheduler add interval=1d name=daily-psk-nightly on-event="/ system script run daily-psk.local;" start-date=may/23/2018 start-time=03:00:00; + / system scheduler add name=daily-psk-startup on-event="/ system script { run global-wait; run daily-psk.local; }" start-time=startup; These will update the passphrase on boot and nightly at 3:00. @@ -61,28 +40,17 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `DailyPskMatchComment`: pattern to match the wireless access list comment * `DailyPskSecrets`: an array with pseudo random strings -> ℹ️ **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. +Then add an access list entry: -Then add an access list entry. For `wifi`: + / interface wireless access-list add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; - /interface/wifi/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily"; +Also notification settings are required for e-mail and telegram. -For legacy CAPsMAN: +See also +-------- - /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; - -For legacy local interface: - - /interface/wireless/access-list/add comment="Daily PSK" interface=wl-daily private-pre-shared-key="ToBeChangedDaily"; - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[trix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). +* [Wait for configuration und functions](global-wait.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/dhcp-lease-comment.md b/doc/dhcp-lease-comment.md index b02f199..caba7d6 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -1,17 +1,7 @@ Comment DHCP leases with info from access list ============================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -22,19 +12,14 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use `wifi` package (`/interface/wifi`), legacy -wifi with CAPsMAN (`/caps-man`) or local wireless interface -(`/interface/wireless`) you need to install a different script. +Depending on whether you use CAPsMAN (`/ caps-man`) or local wireless +interface (`/ interface wireless`) you need to install a different script. -For `wifi`: - - $ScriptInstallUpdate dhcp-lease-comment.wifi; - -For legacy CAPsMAN: +For CAPsMAN: $ScriptInstallUpdate dhcp-lease-comment.capsman; -For legacy local interface: +For local interface: $ScriptInstallUpdate dhcp-lease-comment.local; @@ -60,5 +45,5 @@ See also * [Run other scripts on DHCP lease](lease-script.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/dhcp-to-dns.md b/doc/dhcp-to-dns.md index 4211d85..699b6a5 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -1,24 +1,12 @@ Create DNS records for DHCP leases ================================== -[![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.16-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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- -This script adds (and updates & removes) dns records based on dhcp server -leases. An A record based on mac address is created for all bound lease, -additionally a CNAME record is created from host name if available. +This script adds (and removes) dns records based on dhcp server leases. Requirements and installation ----------------------------- @@ -32,7 +20,7 @@ Then run it from dhcp server as lease script. You may want to use A scheduler cares about cleanup: - /system/scheduler/add interval=15m name=dhcp-to-dns on-event="/system/script/run dhcp-to-dns;" start-time=startup; + / system scheduler add interval=15m name=dhcp-to-dns on-event="/ system script run dhcp-to-dns;" start-time=startup; Configuration ------------- @@ -41,53 +29,20 @@ On first run a disabled static dns record acting as marker (with comment "`--- dhcp-to-dns above ---`") is added. Move this entry to define where new entries are to be added. -The configuration goes to dhcp server's network definition. The domain is -used to form the dns name: - - /ip/dhcp-server/network/add address=10.0.0.0/24 domain=example.com; - -A bound lease for mac address `00:11:22:33:44:55` with ip address -`10.0.0.50` would result in an A record `00-11-22-33-44-55.example.com` -pointing to the given ip address. - -Additional options can be given from comment, to add an extra level in -dns name or define a different domain. - - /ip/dhcp-server/network/add address=10.0.0.0/24 domain=example.com comment="domain=another-domain.com, name-extra=dhcp"; - -This example would result in name `00-11-22-33-44-55.dhcp.another-domain.com` -for the same lease. - -If no domain is found in dhcp server's network definition a fallback from -`global-config-overlay` is used. This is the parameter: +The configuration goes to `global-config-overlay`, these are the parameters: * `Domain`: the domain used for dns records - -> ℹ️ **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. - -### Host name from DHCP lease comment - -Overwriting the host name from dhcp lease comment is supported, just add -something like `hostname=new-hostname` in comment, and separate it by comma -from other information if required: - - /ip/dhcp-server/lease/add address=10.0.0.50 comment="my device, hostname=new-hostname" mac-address=00:11:22:33:44:55 server=dhcp; - -Note this information can be configured in wireless access list with -[dhcp-lease-comment](dhcp-lease-comment.md), though it comes with a delay -then due to script execution order. Decrease the scheduler interval to -reduce the effect. +* `HostNameInZone`: whether or not to add the dhcp/dns server's hostname +* `PrefixInZone`: whether or not to add prefix `dhcp` +* `ServerNameInZone`: whether or not to add DHCP server name See also -------- * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) -* [Create DNS records for IPSec peers](ipsec-to-dns.md) * [Run other scripts on DHCP lease](lease-script.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/early-errors.md b/doc/early-errors.md index b3c6800..a16da7d 100644 --- a/doc/early-errors.md +++ b/doc/early-errors.md @@ -1,2 +1,11 @@ -This script has been replaced. Please migrate to +Send notification with early errors +=================================== + +[◀ Go back to main README](../README.md) + +This script has been replace. Please migrate to [Forward log messages via notification](log-forward.md). + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/email-backup.md b/doc/email-backup.md index d674743..7f89a06 100644 --- a/doc/email-backup.md +++ b/doc/email-backup.md @@ -1 +1,52 @@ -This script has been renamed. Please see [backup-email](backup-email.md). \ No newline at end of file +Send backup via e-mail +====================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script sends binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) via e-mail. + + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate email-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, These are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `EmailBackupTo`: e-mail address to send to +* `EmailBackupCc`: e-mail address(es) to send in copy + +Also valid e-mail settings in `/ tool e-mail` are required to send mails. + +Usage and invocation +-------------------- + +Just run the script: + + / system script run email-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=email-backup on-event="/ system script run email-backup;" start-time=09:15:00; + +See also +-------- + +* [Upload backup to Mikrotik cloud](cloud-backup.md) +* [Upload backup to server](upload-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md deleted file mode 100644 index 54f1da0..0000000 --- a/doc/firmware-upgrade-reboot.md +++ /dev/null @@ -1,43 +0,0 @@ -Automatically upgrade firmware and reboot -========================================= - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -RouterOS and firmware are upgraded separately, activating the latter -requires an extra reboot. This script handles upgrade and reboot. - -> ⚠️ **Warning**: This *should* be bullet proof, but I can not guarantee. In -> worst case it has potential to cause a boot loop, so handle with care! - -Requirements and installation ------------------------------ - -Just install the script and create a scheduler: - - $ScriptInstallUpdate firmware-upgrade-reboot; - /system/scheduler/add name=firmware-upgrade-reboot on-event="/system/script/run firmware-upgrade-reboot;" start-time=startup; - -Enjoy firmware being up to date and in sync with RouterOS. - -See also --------- - -* [Notify on RouterOS update](check-routeros-update.md) -* [Manage system update](packages-update.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md deleted file mode 100644 index cb560d7..0000000 --- a/doc/fw-addr-lists.md +++ /dev/null @@ -1,137 +0,0 @@ -Download, import and update firewall address-lists -================================================== - -[![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.16-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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -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 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. - -To mitigate man-in-the-middle attacks with altered lists the server's -certificate is checked. - -> ⚠️ **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), -> and may take a long time to process. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate fw-addr-lists; - -And add two schedulers, first one for initial import after startup, second -one for subsequent updates: - - /system/scheduler/add name="fw-addr-lists@startup" start-time=startup on-event="/system/script/run fw-addr-lists;"; - /system/scheduler/add name="fw-addr-lists" start-time=startup interval=2h on-event="/system/script/run fw-addr-lists;"; - -> ℹ️ **Info**: Modify the interval to your needs, but it is recommended to -> use less than half of the configured timeout for expiration. - -Configuration -------------- - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `FwAddrLists`: a list of firewall address-lists to download and import -* `FwAddrListTimeOut`: the timeout for expiration without renew - -> ℹ️ **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. - -Naming a certificate for a list makes the script verify the server -certificate, so you should add that if possible. You may want to find the -[certificate name from browser](../CERTIFICATES.md). - -Create firewall rules to process the packets that are related to addresses -from address-lists. - -### IPv4 rules - -This rejects the packets from and to IPv4 addresses listed in -address-list `block`. - - /ip/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ip/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ip/firewall/filter/add chain=forward dst-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ip/firewall/filter/add chain=output dst-address-list=block action=reject reject-with=icmp-admin-prohibited; - -You may want to have an address-list to allow specific addresses, as prepared -with a list `allow`. In fact you can use any list name, just change the -default ones or add your own - matching in configuration and firewall rules. - - /ip/firewall/filter/add chain=input src-address-list=allow action=accept; - /ip/firewall/filter/add chain=forward src-address-list=allow action=accept; - /ip/firewall/filter/add chain=forward dst-address-list=allow action=accept; - /ip/firewall/filter/add chain=output dst-address-list=allow action=accept; - -Modify these for your needs, but **most important**: Move the rules up in -chains and make sure they actually take effect as expected! - -Alternatively handle the packets in firewall's raw section if you prefer: - - /ip/firewall/raw/add chain=prerouting src-address-list=block action=drop; - /ip/firewall/raw/add chain=prerouting dst-address-list=block action=drop; - /ip/firewall/raw/add chain=output dst-address-list=block action=drop; - -> ⚠️ **Warning**: Just again... The order of firewall rules is important. Make -> sure they actually take effect as expected! - -### IPv6 rules - -These are the same rules, but for IPv6. - -Reject packets in address-list `block`: - - /ipv6/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ipv6/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ipv6/firewall/filter/add chain=forward dst-address-list=block action=reject reject-with=icmp-admin-prohibited; - /ipv6/firewall/filter/add chain=output dst-address-list=block action=reject reject-with=icmp-admin-prohibited; - -Allow packets in address-list `allow`: - - /ipv6/firewall/filter/add chain=input src-address-list=allow action=accept; - /ipv6/firewall/filter/add chain=forward src-address-list=allow action=accept; - /ipv6/firewall/filter/add chain=forward dst-address-list=allow action=accept; - /ipv6/firewall/filter/add chain=output dst-address-list=allow action=accept; - -Drop packets in firewall's raw section: - - /ipv6/firewall/raw/add chain=prerouting src-address-list=block action=drop; - /ipv6/firewall/raw/add chain=prerouting dst-address-list=block action=drop; - /ipv6/firewall/raw/add chain=output dst-address-list=block action=drop; - -> ⚠️ **Warning**: Just again... The order of firewall rules is important. Make -> sure they actually take effect as expected! - -See also --------- - -* [Certificate name from browser](../CERTIFICATES.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/global-wait.md b/doc/global-wait.md index 799cae7..bdceddf 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -1,25 +1,16 @@ -Wait for global functions and modules -===================================== +Wait for configuration und functions +==================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- -The global functions from `global-functions` and modules are loaded by -scheduler at system startup. Running these functions at system startup may -result in race condition where configuration and/or function are not yet -available. This script is supposed to wait for everything being prepared. +The global scripts `global-config`, `global-config-overlay` and +`global-functions` are run by scheduler at system startup. Running another +script at system startup may result in race condition where configuration +and/or function are not yet available. This script is supposed to wait +for everything being prepared. Do **not** add this script `global-wait` to the `global-scripts` scheduler! It would inhibit the initialization of configuration and functions. @@ -31,17 +22,19 @@ Just install the script: $ScriptInstallUpdate global-wait; -... and add it to your scheduler, for example in combination with the module -to [manage VLANs on bridge ports](mod/bridge-port-vlan.md): +... and add it to your scheduler, for example in combination with +[bridge-port](bridge-port.md): - /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; + / system scheduler add name=bridge-port-to-default on-event="/ system script { run global-wait; run bridge-port-to-default; }" start-time=startup; See also -------- -* [Manage ports in bridge](mod/bridge-port-to.md) -* [Manage VLANs on bridge ports](mod/bridge-port-vlan.md) +* [Manage ports in bridge](bridge-port.md) +* [Download packages for CAP upgrade from CAPsMAN](capsman-download-packages.md) +* [Renew certificates and notify on expiration](check-certificates.md) +* [Use wireless network with daily psk](daily-psk.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/gps-track.md b/doc/gps-track.md index 5e4878f..cda7901 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -1,17 +1,7 @@ Send GPS position to server =========================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -30,7 +20,7 @@ Just install the script: ... and create a scheduler: - /system/scheduler/add interval=1m name=gps-track on-event="/system/script/run gps-track;" start-time=startup; + / system scheduler add interval=1m name=gps-track on-event="/ system script run gps-track;" start-time=startup; Configuration ------------- @@ -39,13 +29,9 @@ The configuration goes to `global-config-overlay`, the only parameter is: * `GpsTrackUrl`: the url to send json data to -> ℹ️ **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. - -The configured coordinate format (see `/system/gps`) defines the format +The configured coordinate format (see `/ system gps`) defines the format sent to the server. --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/hotspot-to-wpa.md b/doc/hotspot-to-wpa.md index a2e9748..fbb9640 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -1,72 +1,28 @@ -Use WPA network with hotspot credentials -======================================== +Use WPA2 network with hotspot credentials +========================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- RouterOS supports an unlimited number of MAC address specific passphrases -for WPA encrypted wifi networks via access list. The idea of this script -is to transfer hotspot credentials to MAC address specific WPA passphrase. +for WPA2 encrypted wifi networks via access list. The idea of this script +is to transfer hotspot credentials to MAC address specific WPA2 passphrase. Requirements and installation ----------------------------- -You need a properly configured hotspot on one (open) SSID and a WPA enabled +You need a properly configured hotspot on one (open) SSID and a WP2 enabled SSID with suffix "`-wpa`". -Then install the script. -Depending on whether you use `wifi` package (`/interface/wifi`)or legacy -wifi with CAPsMAN (`/caps-man`) you need to install a different script and -set it as `on-login` script in hotspot. +Then install the script: -For `wifi`: + $ScriptInstallUpdate hotspot-to-wpa; - $ScriptInstallUpdate hotspot-to-wpa.wifi; - /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifi" [ find ]; +Configure your hotspot to use this script as `on-login` script: -For legacy CAPsMAN: - - $ScriptInstallUpdate hotspot-to-wpa.capsman; - /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.capsman" [ find ]; - -### Automatic cleanup - -With just `hotspot-to-wpa` installed the mac addresses will last in the -access list forever. Install the optional script for automatic cleanup -and add a scheduler. - -For `wifi`: - - $ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi,lease-script; - /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.wifi;" start-time=startup; - -For legacy CAPsMAN: - - $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,lease-script; - /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.capsman;" start-time=startup; - -And add the lease script and matcher comment to your wpa interfaces' dhcp -server. You can add more information to the comment, separated by comma. In -this example the server is called `hotspot-to-wpa`. - - /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa" hotspot-to-wpa; - -You can specify the timeout after which a device is removed from leases and -access-list. The default is four weeks. - - /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa, timeout=2w" hotspot-to-wpa; + / ip hotspot user profile set on-login=hotspot-to-wpa [ find ]; Configuration ------------- @@ -75,50 +31,18 @@ On first run a disabled access list entry acting as marker (with comment "`--- hotspot-to-wpa above ---`") is added. Move this entry to define where new entries are to be added. -Create hotspot login credentials: - - /ip/hotspot/user/add comment="Test User 1" name=user1 password=v3ry; - /ip/hotspot/user/add comment="Test User 2" name=user2 password=s3cr3t; - -This also works with authentication via radius, but is limited then: -Additional information is not available, including the password. - -Additionally templates can be created to give more options for access list: - -* `action`: set to `reject` to ignore logins on that hotspot -* `passphrase` or `private-passphrase`: do **not** use passphrase from - hotspot's user credentials, but given one - or unset (use default - passphrase) with special word `ignore` -* `ssid-regexp`: set a different SSID regular expression to match -* `vlan-id`: connect device to specific VLAN -* `vlan-mode`: set the VLAN mode for device - -For a hotspot called `example` the template could look like this. -For `wifi`: - - /interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; - -For legacy CAPsMAN: - - /caps-man/access-list/add comment="hotspot-to-wpa template example" disabled=yes private-passphrase="ignore" ssid-regexp="^example\$" vlan-id=10 vlan-mode=use-tag; - -The same settings are available in hotspot user's comment and take precedence -over the template settings: - - /ip/hotspot/user/add comment="private-passphrase=ignore, ssid-regexp=^example\\\$, vlan-id=10, vlan-mode=use-tag" name=user password=v3ry-s3cr3t; - Usage and invocation -------------------- +Create hotspot login credentials: + + / ip hotspot user add add comment="Test User 1" name=user1 password=v3ry; + / ip hotspot user add add comment="Test User 2" name=user2 password=s3cr3t; + Now let the users connect and login to the hotspot. After that the devices -(identified by MAC address) can connect to the WPA network, using the +(identified by MAC address) can connect to the WPA2 network, using the passphrase from hotspot credentials. -See also --------- - -* [Run other scripts on DHCP lease](lease-script.md) - --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/ip-addr-bridge.md b/doc/ip-addr-bridge.md index f9f98e3..44dac6a 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -1,14 +1,7 @@ Manage IP addresses with bridge status ====================================== -[![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) +[◀ Go back to main README](../README.md) Description ----------- @@ -26,14 +19,14 @@ Just install the script: ... and make it run from scheduler: - /system/scheduler/add name=ip-addr-bridge on-event="/system/script/run ip-addr-bridge;" start-time=startup; + / system scheduler add name=ip-addr-bridge on-event="/ system script run ip-addr-bridge;" start-time=startup; -This will disable IP addresses on bridges without at least one running port. +This will disable IP addresses on bridges without at lease one running port. The IP address is enabled if at least one port is running. Note that IP addresses on bridges without a single port (acting as loopback interface) are ignored. --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/ipsec-to-dns.md b/doc/ipsec-to-dns.md deleted file mode 100644 index 123656c..0000000 --- a/doc/ipsec-to-dns.md +++ /dev/null @@ -1,57 +0,0 @@ -Create DNS records for IPSec peers -================================== - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script adds (and removes) dns records based on IPSec peers and their -dynamic addresses from mode-config. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate ipsec-to-dns; - -This script is run from scheduler: - - /system/scheduler/add interval=1m name=ipsec-to-dns on-event="/system/script/run ipsec-to-dns;" start-time=startup; - -Configuration -------------- - -On first run a disabled static dns record acting as marker (with comment -"`--- ipsec-to-dns above ---`") is added. Move this entry to define where new -entries are to be added. - -The configuration goes to `global-config-overlay`, these are the parameters: - -* `Domain`: the domain used for dns records -* `HostNameInZone`: whether or not to add the ipsec/dns server's hostname -* `PrefixInZone`: whether or not to add prefix `ipsec` - -> ℹ️ **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. - -See also --------- - -* [Create DNS records for DHCP leases](dns-to-dhcp.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/ipv6-update.md b/doc/ipv6-update.md index 1f009b1..f736433 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -1,24 +1,14 @@ Update configuration on IPv6 prefix change ========================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- With changing IPv6 prefix from ISP this script handles to update... -* ipv6 firewall address-list (prefixes (`/64`) and host addresses (`/128`)) +* ipv6 firewall address-list * dns records Requirements and installation @@ -30,14 +20,14 @@ Just install the script: Your ISP needs to provide an IPv6 prefix, your device receives it via dhcp: - /ipv6/dhcp-client/add add-default-route=yes interface=ppp-isp pool-name=isp request=prefix script=ipv6-update; + / ipv6 dhcp-client add add-default-route=yes interface=ppp-isp pool-name=isp request=prefix script=ipv6-update; Note this already adds this script as `script`. The pool name (here: "`isp`") is important, we need it later. Also this expects there is an address assigned from pool to an interface: - /ipv6/address/add from-pool=isp interface=br-local; + / ipv6 address add from-pool=isp interface=br-local; Sometimes dhcp client is stuck on reconnect and needs to be released. Installing [ppp-on-up](ppp-on-up.md) may solve this. @@ -45,34 +35,25 @@ Installing [ppp-on-up](ppp-on-up.md) may solve this. Configuration ------------- -As an address-list entry is mandatory a dynamic one is created automatically. -It is updated with current prefix and can be used in firewall rules. +An address list entry is updated with current prefix and can be used in +firewall rules, comment has to be "`ipv6-pool-`" and actual pool name: -Alternatively a static address-list entry can be used, where comment has to -be "`ipv6-pool-`" and actual pool name. Use what ever list is desired, and -create it with: + / ipv6 firewall address-list add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; - /ipv6/firewall/address-list/add address=2003:cf:2f0f:de00::/56 comment=ipv6-pool-isp list=extern; - -If the dynamic entry exists already you need to remove it before creating -the static one.. +As this entry is mandatory it is created automatically if it does not exist, +with the comment also set for list. Address list entries for specific interfaces can be updated as well. The interface needs to get its address from pool `isp` and the address list entry has to be associated to an interface in comment: - /ipv6/firewall/address-list/add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; - -Updating address list entries with host addresses works as well, the new -prefix is combinded with given suffix then: - - /ipv6/firewall/address-list/add address=2003:cf:2f0f:de01:e3e0:f8fa:8cd6:dbe1/128 comment="ipv6-pool-isp, interface=br-local" list=hosts; + / ipv6 firewall address-list add address=2003:cf:2f0f:de01::/64 comment="ipv6-pool-isp, interface=br-local" list=local; Static DNS records need a special comment to be updated. Again it has to start with "`ipv6-pool-`" and actual pool name, followed by a comma, "`interface=`" and the name of interface this address is connected to: - /ip/dns/static/add address=2003:cf:2f0f:de00:1122:3344:5566:7788 comment="ipv6-pool-isp, interface=br-local" name=test.example.com ttl=15m; + / ip dns static add address=2003:cf:2f0f:de00:1122:3344:5566:7788 comment="ipv6-pool-isp, interface=br-local" name=test.example.com ttl=15m; See also -------- @@ -80,5 +61,5 @@ See also * [Run scripts on ppp connection](ppp-on-up.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/lease-script.md b/doc/lease-script.md index f83c383..3c774f1 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -1,34 +1,17 @@ Run other scripts on DHCP lease =============================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- -This script is supposed to run from dhcp server as lease script. On a dhcp -lease it runs each script containing the following line, where `##` is a -decimal number for ordering: +This script is supposed to run from dhcp server as lease script. Currently +it does: - # provides: lease-script, order=## - -Currently it runs if available, in order: - -* [dhcp-to-dns](dhcp-to-dns.md) -* [collect-wireless-mac](collect-wireless-mac.md) -* [dhcp-lease-comment](dhcp-lease-comment.md) -* `hotspot-to-wpa-cleanup`, which is an optional cleanup script - of [hotspot-to-wpa](hotspot-to-wpa.md) +* run [dhcp-to-dns](dhcp-to-dns.md) +* run [collect-wireless-mac](collect-wireless-mac.md) +* run [dhcp-lease-comment](dhcp-lease-comment.md) Requirements and installation ----------------------------- @@ -39,7 +22,7 @@ Just install the script: ... and add it as `lease-script` to your dhcp server: - /ip/dhcp-server/set lease-script=lease-script [ find ]; + / ip dhcp-server set lease-script=lease-script [ find ]; See also -------- @@ -47,8 +30,7 @@ See also * [Collect MAC addresses in wireless access list](collect-wireless-mac.md) * [Comment DHCP leases with info from access list](dhcp-lease-comment.md) * [Create DNS records for DHCP leases](dhcp-to-dns.md) -* [Use WPA network with hotspot credentials](hotspot-to-wpa.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/leds-mode.md b/doc/leds-mode.md index a194396..b525220 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -1,14 +1,7 @@ Manage LEDs dark mode ===================== -[![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) +[◀ Go back to main README](../README.md) Description ----------- @@ -28,21 +21,21 @@ Usage and invocation To switch the device to dark mode: - /system/script/run leds-night-mode; + / system script run leds-night-mode; ... and back to normal mode: - /system/script/run leds-day-mode; + / system script run leds-day-mode; To toggle between the two modes: - /system/script/run leds-toggle-mode; + / system script run leds-toggle-mode; Add these schedulers to switch to dark mode in the evening and back to normal mode in the morning: - /system/scheduler/add interval=1d name=leds-day-mode on-event="/system/script/run leds-day-mode;" start-time=07:00:00; - /system/scheduler/add interval=1d name=leds-night-mode on-event="/system/script/run leds-night-mode;" start-time=21:00:00; + / system scheduler add interval=1d name=leds-day-mode on-event="/ system script run leds-day-mode;" start-time=07:00:00; + / system scheduler add interval=1d name=leds-night-mode on-event="/ system script run leds-night-mode;" start-time=21:00:00; The script `leds-toggle-mode` can be used from [mode button](mode-button.md) to toggle mode. @@ -53,5 +46,5 @@ See also * [Mode button with multiple presses](mode-button.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/log-forward.d/notification.avif b/doc/log-forward.d/notification.avif deleted file mode 100644 index a0f9ab3..0000000 Binary files a/doc/log-forward.d/notification.avif and /dev/null differ diff --git a/doc/log-forward.md b/doc/log-forward.md index 3c19569..afb695e 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -1,43 +1,21 @@ Forward log messages via notification ===================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- -RouterOS itself supports sending log messages via e-mail or to a syslog -server (see `/system/logging`). This has some limitation, however: +RouterOS supports sending log messages via e-mail or to a syslog server. +This has some limitation, however: * does not work early after boot if network connectivity is not - yet established, or breaks intermittently + yet established * lots of messages generate a flood of mails -* Matrix, Ntfy and Telegram are not supported +* Telegram is 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*, *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. - -### Sample notification - -![log-forward notification](log-forward.d/notification.avif) +The script is intended to be run periodically. It collects log messages +and forwards them via notification. Requirements and installation ----------------------------- @@ -48,54 +26,18 @@ Just install the script: ... and add a scheduler: - /system/scheduler/add interval=1m name=log-forward on-event="/system/script/run log-forward;" start-time=startup; + / system scheduler add interval=1m name=log-forward on-event="/ system script run log-forward;" start-time=startup; 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 * `LogForwardFilterMessage`: define message text *not* to be forwarded -* `LogForwardInclude`: define topics to be forwarded (even if filter matches) -* `LogForwardIncludeMessage`: define message text to be forwarded (even if - filter matches) -> ℹ️ **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. - -These patterns are matched as -[regular expressions](https://wiki.mikrotik.com/wiki/Manual:Regular_Expressions). -To forward **all** (ignoring severity) log messages with topics `account` -(which includes user logins) and `dhcp` you need something like: - - :global LogForwardInclude "(account|dhcp)"; - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). - -Tips & Tricks -------------- - -### Notification on reboot - -You want to receive a notification on every device (re-)boot? Quite easy, -just add: - - :global LogForwardIncludeMessage "(^router rebooted)"; - -This will match on every log message beginning with `router rebooted`. +Also notification settings are required for e-mail and telegram. --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/mod/bridge-port-to.md b/doc/mod/bridge-port-to.md deleted file mode 100644 index 629c526..0000000 --- a/doc/mod/bridge-port-to.md +++ /dev/null @@ -1,88 +0,0 @@ -Manage ports in bridge -====================== - -[![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) - -> ℹ️️ **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 and its functio are are supposed to handle interfaces and -switching them from one bridge to another. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/bridge-port-to; - -Configuration -------------- - -The configuration goes to ports' comments (`/interface/bridge/port`). - - /interface/bridge/port/add bridge=br-guest comment="default=dhcp-client, alt=br-guest" disabled=yes interface=en1; - /interface/bridge/port/add bridge=br-intern comment="default=br-intern, alt=br-guest" interface=en2; - /interface/bridge/port/add bridge=br-guest comment="default=br-guest, extra=br-extra" interface=en3; - -Also dhcp client can be handled: - - /ip/dhcp-client/add comment="toggle with bridge port" disabled=no interface=en1; - -Add a scheduler to start with default setup on system startup: - - $ScriptInstallUpdate global-wait; - /system/scheduler/add name=bridge-port-to on-event="/system/script/run global-wait; :global BridgePortTo; \$BridgePortTo default;" start-time=startup; - -Usage and invocation --------------------- - -The usage examples show what happens with the configuration from above. - -Running the function `$BridgePortTo` with parameter `default` applies all -configuration given with `default=`: - - $BridgePortTo default; - -For the three interfaces we get this configuration: - -* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. -* Interface `en2` is put in bridge `br-intern`. -* Interface `en3` is put in bridge `br-guest`. - -Running the function `$BridgePortTo` with parameter `alt` applies all -configuration given with `alt=`: - - $BridgePortTo alt; - -* Interface `en1` is put in bridge `br-guest`, dhcp client for the interface is disabled. -* Interface `en2` is put in bridge `br-guest`. -* Interface `en3` is unchanged, stays in bridge `br-guest`. - -Running the function `$BridgePortTo` with parameter `extra` applies another -configuration: - - $BridgePortTo extra; - -* Interfaces `en1` and `en2` are unchanged. -* Interface `en3` is put in bridge `br-intern`. - -See also --------- - -* [Wait for global functions und modules](../global-wait.md) -* [Manage VLANs on bridge ports](bridge-port-vlan.md) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md deleted file mode 100644 index cf29199..0000000 --- a/doc/mod/bridge-port-vlan.md +++ /dev/null @@ -1,92 +0,0 @@ -Manage VLANs on bridge ports -============================ - -[![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) - -> ℹ️️ **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 and its function are supposed to handle VLANs on bridge ports. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/bridge-port-vlan; - -Configuration -------------- - -Using named VLANs you have to add comments in bridge vlan menu: - - /interface/bridge/vlan/add bridge=bridge comment=intern tagged=br-local vlan-ids=10; - /interface/bridge/vlan/add bridge=bridge comment=geust tagged=br-local vlan-ids=20; - /interface/bridge/vlan/add bridge=bridge comment=extra tagged=br-local vlan-ids=30; - -The configuration goes to ports' comments (`/interface/bridge/port`). - - /interface/bridge/port/add bridge=bridge comment="default=dhcp-client, alt=guest" disabled=yes interface=en1; - /interface/bridge/port/add bridge=bridge comment="default=intern, alt=guest, extra=30" interface=en2; - /interface/bridge/port/add bridge=bridge comment="default=guest, extra=extra" interface=en3; - -Also dhcp client can be handled: - - /ip/dhcp-client/add comment="toggle with bridge port" disabled=no interface=en1; - -Add a scheduler to start with default setup on system startup: - - $ScriptInstallUpdate global-wait; - /system/scheduler/add name=bridge-port-vlan on-event="/system/script/run global-wait; :global BridgePortVlan; \$BridgePortVlan default;" start-time=startup; - -Usage and invocation --------------------- - -The usage examples show what happens with the configuration from above. - -Running the function `$BridgePortVlan` with parameter `default` applies all -configuration given with `default=`: - - $BridgePortVlan default; - -For the three interfaces we get this configuration: - -* The special value `dhcp-client` enables the dhcp client for interface `en1`. The bridge port entry is disabled. -* Primary VLAN `intern` (ID `10`) is configured on `en2`. -* Primary VLAN `guest` (ID `20`) is configured on `en3`. - -Running the function `$BridgePortVlan` with parameter `alt` applies all -configuration given with `alt=`: - - $BridgePortVlan alt; - -* Primary VLAN `guest` (ID `20`) is configured on `en1`, dhcp client for the interface is disabled. -* Primary VLAN `guest` (ID `20`) is configured on `en2`. -* Interface `en3` is unchanged, primary VLAN `guest` (ID `20`) is unchanged. - -Running the function `$BridgePortVlan` with parameter `extra` applies another -configuration: - -* Interface `en1` is unchanged. -* Primary VLAN `extra` (via its ID `30`) is configured on `en2`. -* Primary VLAN `extra` (ID `30`) is configured on `en3`. - -See also --------- - -* [Wait for global functions und modules](../global-wait.md) -* [Manage ports in bridge](bridge-port-to.md) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/inspectvar.d/inspectvar.avif b/doc/mod/inspectvar.d/inspectvar.avif deleted file mode 100644 index f1da1d4..0000000 Binary files a/doc/mod/inspectvar.d/inspectvar.avif and /dev/null differ diff --git a/doc/mod/inspectvar.md b/doc/mod/inspectvar.md deleted file mode 100644 index 7daba15..0000000 --- a/doc/mod/inspectvar.md +++ /dev/null @@ -1,40 +0,0 @@ -Inspect variables -================= - -[![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) - -> ℹ️️ **Info**: This module can not be used on its own but requires the base -> installation. See [main README](../../README.md) for details. - -Description ------------ - -RouterOS handles not just scalar variables, but also arrays - even nested. -This module adds a function to inspect variables. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/inspectvar; - -Usage and invocation --------------------- - -Call the function `$InspectVar` with a variable as parameter: - - $InspectVar $ModeButton; - -![InspectVar](inspectvar.d/inspectvar.avif) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/ipcalc.d/ipcalc.avif b/doc/mod/ipcalc.d/ipcalc.avif deleted file mode 100644 index fe726e8..0000000 Binary files a/doc/mod/ipcalc.d/ipcalc.avif and /dev/null differ diff --git a/doc/mod/ipcalc.d/ipcalcreturn.avif b/doc/mod/ipcalc.d/ipcalcreturn.avif deleted file mode 100644 index 5e4dd57..0000000 Binary files a/doc/mod/ipcalc.d/ipcalcreturn.avif and /dev/null differ diff --git a/doc/mod/ipcalc.md b/doc/mod/ipcalc.md deleted file mode 100644 index c07853e..0000000 --- a/doc/mod/ipcalc.md +++ /dev/null @@ -1,60 +0,0 @@ -IP address calculation -====================== - -[![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) - -> ℹ️️ **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 functions for IP address calculation. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/ipcalc; - -Usage and invocation --------------------- - -### IPCalc - -The function `$IPCalc` prints information to terminal, including: - -* address -* netmask -* network in CIDR notation -* minimum host address -* maximum host address -* broadcast address - -It expects an IP address in CIDR notation as argument. - - $IPCalc 192.168.88.1/24; - -![IPCalc](ipcalc.d/ipcalc.avif) - -### IPCalcReturn - -The function `$IPCalcReturn` expects an IP address in CIDR notation as -argument as well. But it does not print to terminal, instead it returns -the information in a named array. - - :put ([ $IPCalcReturn 192.168.88.1/24 ]->"broadcast"); - -![IPCalcReturn](ipcalc.d/ipcalcreturn.avif) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/notification-email.md b/doc/mod/notification-email.md deleted file mode 100644 index 34d1c09..0000000 --- a/doc/mod/notification-email.md +++ /dev/null @@ -1,88 +0,0 @@ -Send notifications via e-mail -============================= - -[![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) - -> ℹ️️ **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 e-mail. 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-email; - -Also you need a valid e-mail account with smtp login credentials. - -Configuration -------------- - -Set up your device's -[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 -the ntp client. - -Then edit `global-config-overlay`, add `EmailGeneralTo` with a valid -recipient address. Finally 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. - -### Sending to several recipients - -Sending notifications to several recipients is possible as well. Add -`EmailGeneralCc` on top, which can have a single mail address or a comma -separated list. - -Usage and invocation --------------------- - -There's nothing special to do. Every script or function sending a notification -will now send it to your e-mail account. - -But of course you can use the function to send notifications directly. Give -it a try: - - $SendEMail "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 SendEMail; - :global SendNotification; - -In case there is a situation when the queue needs to be purged there is a -function available: - - $PurgeEMailQueue; - -See also --------- - -* [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) diff --git a/doc/mod/notification-matrix.d/01-authenticate.avif b/doc/mod/notification-matrix.d/01-authenticate.avif deleted file mode 100644 index b897943..0000000 Binary files a/doc/mod/notification-matrix.d/01-authenticate.avif and /dev/null differ diff --git a/doc/mod/notification-matrix.d/02-join-room.avif b/doc/mod/notification-matrix.d/02-join-room.avif deleted file mode 100644 index ad99ffd..0000000 Binary files a/doc/mod/notification-matrix.d/02-join-room.avif and /dev/null differ diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md deleted file mode 100644 index 89c1b01..0000000 --- a/doc/mod/notification-matrix.md +++ /dev/null @@ -1,139 +0,0 @@ -Send notifications via Matrix -============================= - -[![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) - -> ℹ️️ **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 -[Matrix](https://matrix.org/) via client server api. 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-matrix; - -Also install a Matrix client on at least one of your mobile and/or desktop -devices. Create and setup an account there, we will reference that as -"*general account*" later. - -Configuration -------------- - -Edit `global-config-overlay`, add `MatrixHomeServer`, `MatrixAccessToken` and -`MatrixRoom` - see below on hints how to retrieve this information. 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. - -The Matrix server is connected via encrypted https, and certificate -verification is applied. So make sure you have the certificate chain for -your server in device's certificate store. - -The example below is for `matrix.org`, which uses a trust chain from *Google -Trust Services*. Run this to import the required certificate: - - $CertificateAvailable "GTS Root R4"; - -Replace the CA certificate name with what ever is needed for your server. -You may want to find the -[certificate name from browser](../../CERTIFICATES.md). - -### From other device - -If you have setup your Matrix *notification account* before just reuse that. -Copy the relevant configuration to the device to be configured. - -### Setup new account - -As there is no privilege separation you should create a dedicated account -for use with these scripts, in addition to your *general account*. -We will reference that as "*notification account*" in the following steps. - -#### Authenticate - -Matrix user accounts are identified by a unique user id in the form of -`@localpart:domain`. Use that and your password to generate an access token -and write first part of the configuration: - - $SetupMatrixAuthenticate "@example:matrix.org" "v3ry-s3cr3t"; - -![authenticate](notification-matrix.d/01-authenticate.avif) - -The configuration is written to a new configuration snippet -`global-config-overlay.d/mod/notification-matrix`. - -#### Join Room - -Every Matix chat is a room, so we have to create one. Do that with your -*general account*, this makes sure your *general account* is the room owner. -Then join the room and invite the *notification account* by its user id -"*@example:matrix.org*". -Look up the *room id* within the Matrix client, it should read like -"*!WUcxpSjKyxSGelouhA:matrix.org*" (starting with an exclamation mark and -ending with the domain). - -Finally make the *notification account* join into the room by accepting -the invite. - - $SetupMatrixJoinRoom "!WUcxpSjKyxSGelouhA:matrix.org"; - -![join room](notification-matrix.d/02-join-room.avif) - -The configuration is appended to the configuration snippet -`global-config-overlay.d/mod/notification-matrix`. - -Usage and invocation --------------------- - -There's nothing special to do. Every script or function sending a notification -will now send it to your Matrix account. - -But of course you can use the function to send notifications directly. Give -it a try: - - $SendMatrix "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 SendMatrix; - :global SendNotification; - -In case there is a situation when the queue needs to be purged there is a -function available: - - $PurgeMatrixQueue; - -See also --------- - -* [Certificate name from browser](../../CERTIFICATES.md) -* [Send notifications via e-mail](notification-email.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) diff --git a/doc/mod/notification-ntfy.md b/doc/mod/notification-ntfy.md deleted file mode 100644 index 51756ac..0000000 --- a/doc/mod/notification-ntfy.md +++ /dev/null @@ -1,98 +0,0 @@ -Send notifications via Ntfy -=========================== - -[![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) - -> ℹ️️ **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 -[Ntfy](https://ntfy.sh/). 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-ntfy; - -Also install the Ntfy app on your mobile device or use the -[web app](https://ntfy.sh/app) in a browser of your choice. - -Configuration -------------- - -Creating an account is not required. Just choose a topic and you are good -to go. - -> ⚠️ **Warning**: If you use ntfy without sign-up, the topic is essentially -> a password, so pick something that's not easily guessable. - -Edit `global-config-overlay`, add `NtfyServer` (leave it unchanged, unless -you are self-hosting the service) and `NtfyTopic` with your choosen topic. -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. - -Using a paid account or running a server on-premises allows to add additional -basic authentication. Configure `NtfyServerUser` and `NtfyServerPass` for this. -Even authentication via access token is possible, adding it as password with -a blank username. - -Also available is `NtfyServerToken` to add a bearer token for authentication. - -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 Ntfy topic. - -But of course you can use the function to send notifications directly. Give -it a try: - - $SendNtfy "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 SendNtfy; - :global SendNotification; - -In case there is a situation when the queue needs to be purged there is a -function available: - - $PurgeNtfyQueue; - -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 Telegram](notification-telegram.md) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/notification-telegram.d/getchatid.avif b/doc/mod/notification-telegram.d/getchatid.avif deleted file mode 100644 index 7792969..0000000 Binary files a/doc/mod/notification-telegram.d/getchatid.avif and /dev/null differ diff --git a/doc/mod/notification-telegram.d/newbot.avif b/doc/mod/notification-telegram.d/newbot.avif deleted file mode 100644 index 1fc7355..0000000 Binary files a/doc/mod/notification-telegram.d/newbot.avif and /dev/null differ diff --git a/doc/mod/notification-telegram.d/setuserpic.avif b/doc/mod/notification-telegram.d/setuserpic.avif deleted file mode 100644 index 2017d20..0000000 Binary files a/doc/mod/notification-telegram.d/setuserpic.avif and /dev/null differ diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md deleted file mode 100644 index 2d00116..0000000 --- a/doc/mod/notification-telegram.md +++ /dev/null @@ -1,123 +0,0 @@ -Send notifications via Telegram -=============================== - -[![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) - -> ℹ️️ **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 -[Telegram](https://telegram.org/) via bot api. 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-telegram; - -Also install Telegram on at least one of your mobile and/or desktop devices -and create an account. - -Configuration -------------- - -Open Telegram, then start a chat with [BotFather](https://t.me/BotFather) and -create your own bot: - -![create new bot](notification-telegram.d/newbot.avif) - -Set that token from *BotFather* (use your own!) to `TelegramTokenId`, for -now just temporarily: - - :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 retrieved chat id. 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. - -### Notifications to a 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 --------------------- - -There's nothing special to do. Every script or function sending a notification -will now send it to your Telegram account. - -But of course you can use the function to send notifications directly. Give -it a try: - - $SendTelegram "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 SendTelegram; - :global SendNotification; - -In case there is a situation when the queue needs to be purged there is a -function available: - - $PurgeTelegramQueue; - -Tips & Tricks -------------- - -### Set a profile photo - -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. - -![set profile photo](notification-telegram.d/setuserpic.avif) - -Have a look at my -[RouterOS-Scripts Logo Color Changer](https://git.eworm.de/cgit/routeros-scripts/plain/contrib/logo-color.html) -to create a colored version of this scripts' logo. - -See also --------- - -* [Chat with your router and send commands via Telegram bot](../telegram-chat.md) -* [Send notifications via e-mail](notification-email.md) -* [Send notifications via Matrix](notification-matrix.md) -* [Send notifications via Ntfy](notification-ntfy.md) - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/scriptrunonce.d/hello-world.rsc b/doc/mod/scriptrunonce.d/hello-world.rsc deleted file mode 100644 index 6404781..0000000 --- a/doc/mod/scriptrunonce.d/hello-world.rsc +++ /dev/null @@ -1,3 +0,0 @@ -#!rsc by RouterOS - -:put ("Hello World from " . [ /system/identity/get name ] . "!"); diff --git a/doc/mod/scriptrunonce.d/scriptrunonce.avif b/doc/mod/scriptrunonce.d/scriptrunonce.avif deleted file mode 100644 index 27ccd41..0000000 Binary files a/doc/mod/scriptrunonce.d/scriptrunonce.avif and /dev/null differ diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md deleted file mode 100644 index 955d12e..0000000 --- a/doc/mod/scriptrunonce.md +++ /dev/null @@ -1,59 +0,0 @@ -Download script and run it once -=============================== - -[![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) - -> ℹ️️ **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 a function that downloads a script, checks for syntax -validity and runs it once. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/scriptrunonce; - -Configuration -------------- - -The optional configuration goes to `global-config-overlay`. - -* `ScriptRunOnceBaseUrl`: base url, prepended to parameter -* `ScriptRunOnceUrlSuffix`: url suffix, appended to parameter - -> ℹ️ **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. - -If the parameter passed to the function is not a complete URL (starting -with protocol `ftp://`, `http://`, `https://` or `sftp://`) the base-url is -prepended, and file extension `.rsc` and url-suffix are appended. - -Usage and invocation --------------------- - -The function `$ScriptRunOnce` expects an URL (or name if -`ScriptRunOnceBaseUrl` is given) pointing to a script as parameter. - - $ScriptRunOnce https://git.eworm.de/cgit/routeros-scripts/plain/doc/mod/scriptrunonce.d/hello-world.rsc; - -![ScriptRunOnce](scriptrunonce.d/scriptrunonce.avif) - -Giving multiple scripts is possible, separated by comma. - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mod/ssh-keys-import.md b/doc/mod/ssh-keys-import.md deleted file mode 100644 index 344f4bc..0000000 --- a/doc/mod/ssh-keys-import.md +++ /dev/null @@ -1,69 +0,0 @@ -Import ssh keys for public key authentication -============================================= - -[![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.16-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) - -> ℹ️️ **Info**: This module can not be used on its own but requires the base -> installation. See [main README](../../README.md) for details. - -Description ------------ - -RouterOS supports ssh login with public key authentication. The functions -in this module help importing the keys. - -Requirements and installation ------------------------------ - -Just install the module: - - $ScriptInstallUpdate mod/ssh-keys-import; - -Usage and invocation --------------------- - -### Import single key from terminal - -Call the function `$SSHKeysImport` with key and user as parameter to -import that key: - - $SSHKeysImport "ssh-ed25519 AAAAC3Nza...ZVugJT user" admin; - $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; - -The third part of the key (`user` in this example) is inherited as -`key-owner` in RouterOS. Also the `MD5` fingerprint is recorded, this helps -to audit and verify the available keys. - -> ℹ️️ **Info**: Use `ssh-keygen` to show a fingerprint of an existing public -> key file: `ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub` - -### Import several keys from file - -The functions `$SSHKeysImportFile` can read an `authorized_keys`-style file -and import all the keys. The user given to the function can be overwritting -from comments in the file. Create a file `keys.pub` with this content: - -``` -ssh-ed25519 AAAAC3Nza...3OcN8A user@client -ssh-rsa AAAAB3Nza...ozyts= worker@station -# user=example -ssh-rsa AAAAB3Nza...GXQVk= person@host -``` - -Then import it with: - - $SSHKeysImportFile keys.pub admin; - -This will import the first two keys for user `admin` (as given to function) -and the third one for user `example` (as defined in comment). - ---- -[⬅️ Go back to main README](../../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/mode-button.md b/doc/mode-button.md index be15bc9..8d037e5 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -1,17 +1,7 @@ Mode button with multiple presses ================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -20,17 +10,17 @@ This script extend the functionality of mode button. Instead of just one you can trigger several actions by pressing the mode button several times. The hardware needs to have a mode button, see -`/system/routerboard/mode-button`. Starting with RouterOS 6.47beta60 you +`/ system routerboard mode-button`. Starting with RouterOS 6.47beta60 you can configure the reset button to act the same, see -`/system/routerboard/reset-button`. +`/ system routerboard reset-button`. Copy this code to terminal to check: ``` -:if ([ :len [ /system/routerboard/mode-button/print as-value ] ] > 0) do={ +:if ([ :len [ /system routerboard mode-button print as-value ] ] > 0) do={ :put "Mode button is supported."; } else={ - :if ([ :len [ /system/routerboard/reset-button/print as-value ] ] > 0) do={ + :if ([ :len [ /system routerboard reset-button print as-value ] ] > 0) do={ :put "Mode button is not supported, but reset button is."; } else={ :put "Neither mode button nor reset button is supported."; @@ -47,11 +37,11 @@ Just install the script: Then configure the mode button to run `mode-button`: - /system/routerboard/mode-button/set enabled=yes on-event="/system/script/run mode-button;"; + / system routerboard mode-button set enabled=yes on-event="/ system script run mode-button;"; To use the reset button instead: - /system/routerboard/reset-button/set enabled=yes on-event="/system/script/run mode-button;"; + / system routerboard reset-button set enabled=yes on-event="/ system script run mode-button;"; Configuration ------------- @@ -59,17 +49,13 @@ Configuration The configuration goes to `global-config-overlay`, these are the parameters: * `ModeButton`: an array with defined actions -* `ModeButtonLED`: led to give visual feedback, `type` must be `on` or `off` - -> ℹ️ **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. +* `ModeButtonLED`: led to give visual feedback Usage and invocation -------------------- -Press the mode button. 😜 +Press the mode button. :) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/netwatch-dns.md b/doc/netwatch-dns.md deleted file mode 100644 index 0d94918..0000000 --- a/doc/netwatch-dns.md +++ /dev/null @@ -1,99 +0,0 @@ -Manage DNS and DoH servers from netwatch -======================================== - -[![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.16-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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script reads server state from netwatch and manages used DNS and -DoH (DNS over HTTPS) servers. - -Requirements and installation ------------------------------ - -Just install the script: - - $ScriptInstallUpdate netwatch-dns; - -Then add a scheduler to run it periodically: - - /system/scheduler/add interval=1m name=netwatch-dns on-event="/system/script/run netwatch-dns;" start-time=startup; - -Configuration -------------- - -The DNS and DoH servers to be checked have to be added to netwatch with -specific comment: - - /tool/netwatch/add comment="doh" host=1.1.1.1; - /tool/netwatch/add comment="dns" host=8.8.8.8; - /tool/netwatch/add comment="doh, dns" host=9.9.9.9; - -This will configure *cloudflare-dns* for DoH (`https://1.1.1.1/dnsquery`), and -*google-dns* and *quad-nine* for regular DNS (`8.8.8.8,9.9.9.9`) if up. -If *cloudflare-dns* is down the script will fall back to *quad-nine* for DoH. - -Giving a specific query url for DoH is possible: - - /tool/netwatch/add comment="doh, doh-url=https://dns.nextdns.io/dns-query" host=199.247.16.158; - -Note that using a name in DoH url may introduce a chicken-and-egg issue! - -Adding a static DNS record has the same result for the url, but always -resolves to the same address. - - /ip/dns/static/add name="cloudflare-dns.com" address=1.1.1.1; - /tool/netwatch/add comment="doh" host=1.1.1.1; - -Be aware that you have to keep the ip address in sync with real world -manually! - -Importing a certificate automatically is possible. You may want to find the -[certificate name from browser](../CERTIFICATES.md). - - /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G2" host=1.1.1.1; - /tool/netwatch/add comment="doh, doh-cert=DigiCert Global Root G3" host=9.9.9.9; - /tool/netwatch/add comment="doh, doh-cert=GTS Root R1" host=8.8.8.8; - -> ⚠️ **Warning**: Combining these techniques can cause some confusion and -> troubles! Chances are that a service uses different certificates based -> on indicated server name. - -Sometimes using just one specific (possibly internal) DNS server may be -desired, with fallback in case it fails. This is possible as well: - - /tool/netwatch/add comment="dns" host=10.0.0.10; - /tool/netwatch/add comment="dns-fallback" host=1.1.1.1; - -Tips & Tricks -------------- - -### Use in combination with notifications - -Netwatch entries can be created to work with both - this script and -[netwatch-notify](netwatch-notify.md). Just give options for both: - - /tool/netwatch/add comment="doh, notify, name=cloudflare-dns" host=1.1.1.1; - -Also this allows to update host address, see option `resolve`. - -See also --------- - -* [Certificate name from browser](../CERTIFICATES.md) -* [Notify on host up and down](netwatch-notify.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/netwatch-notify.d/notification-01-down.avif b/doc/netwatch-notify.d/notification-01-down.avif deleted file mode 100644 index 894fb23..0000000 Binary files a/doc/netwatch-notify.d/notification-01-down.avif and /dev/null differ diff --git a/doc/netwatch-notify.d/notification-02-up.avif b/doc/netwatch-notify.d/notification-02-up.avif deleted file mode 100644 index 9021a93..0000000 Binary files a/doc/netwatch-notify.d/notification-02-up.avif and /dev/null differ diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 81adfe9..11371ff 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -1,32 +1,17 @@ Notify on host up and down ========================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- This script sends notifications about host UP and DOWN events. In comparison -to just netwatch (`/tool/netwatch`) and its `up-script` and `down-script` +to just netwatch (`/ tool netwatch`) and its `up-script` and `down-script` this script implements a simple state machine and dependency model. Host down events are triggered only if the host is down for several checks and optional parent host is not down to avoid false alerts. -### Sample notifications - -![netwatch-notify notification down](netwatch-notify.d/notification-01-down.avif) -![netwatch-notify notification up](netwatch-notify.d/notification-02-up.avif) - Requirements and installation ----------------------------- @@ -36,159 +21,36 @@ Just install the script: Then add a scheduler to run it periodically: - /system/scheduler/add interval=1m name=netwatch-notify on-event="/system/script/run netwatch-notify;" start-time=startup; + / system scheduler add interval=1m name=netwatch-notify on-event="/ system script run netwatch-notify;" start-time=startup; Configuration ------------- The hosts to be checked have to be added to netwatch with specific comment: - /tool/netwatch/add comment="notify, name=example.com" host=[ :resolve "example.com" ]; - -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). - -### Hooks + / tool netwatch add comment="notify, hostname=example.com" host=[ :resolve "example.com" ]; It is possible to run an up hook command (`up-hook`) or down hook command (`down-hook`) when a notification is triggered. This has to be added in -comment, note that some characters need extra escaping: +comment: - /tool/netwatch/add comment=("notify, name=device, down-hook=/interface/ethernet \\{ disable \\\"en2\\\"; enable \\\"en2\\\"; \\}") host=10.0.0.20; + / tool netwatch add comment="notify, hostname=poe-device, down-hook=/ interface ethernet poe power-cycle en21;" host=10.0.0.20; -Also there is a `pre-down-hook` that fires at two thirds of failed checks -required for the notification. The idea is to fix the issue before a -notification is sent. +The count threshould (default is 5 checks) is configurable as well: -Getting the escaping right may be troublesome. Please consider adding a -script in `/system/script`, then running that from hook. - -### Count threshold - -The count threshold (default is 5 checks) is configurable as well: - - /tool/netwatch/add comment="notify, name=example.com, count=10" host=104.18.144.11; - -### Parents & dependencies + / tool netwatch add comment="notify, hostname=example.com, count=10" host=104.18.144.11; If the host is behind another checked host add a dependency, this will suppress notification if the parent host is down: - /tool/netwatch/add comment="notify, name=gateway" host=93.184.216.1; - /tool/netwatch/add comment="notify, name=example.com, parent=gateway" host=93.184.216.34; + / tool netwatch add comment="notify, hostname=gateway" host=93.184.216.1; + / tool netwatch add comment="notify, hostname=example.com, parent=gateway" host=93.184.216.34; Note that every configured parent in a chain increases the check count -threshold by one. +threshould by one. -### Update from DNS - -The host address can be updated dynamically. Give extra parameter `resolve` -with a resolvable name: - - /tool/netwatch/add comment="notify, name=example.com, resolve=example.com" host=0.0; - -This supports multiple A records for a name just fine, even a CNAME -to those. An update happens only if no more record with the configured host -address is found. - -The address family is preserved, so if you want AAAA records (for IPv6) -use this: - - /tool/netwatch/add comment="notify, name=example.com, resolve=example.com" host=::; - -### No notification on host down - -Also suppressing the notification on host down is possible with parameter -`no-down-notification`. This may be desired for devices that are usually -powered off, but accessibility is of interest. - - /tool/netwatch/add comment="notify, name=printer, no-down-notification" host=10.0.0.30; - -Go and get your coffee ☕️ before sending the print job. - -### No log on failed resolve - -A message is writting to log after three failed attemts to resolve a host. -However this can cause some noise for hosts that are expected to have -failures, for example when the name is dynamically added by -[`dhcp-to-dns`](dhcp-to-dns.md). This can be suppressed: - - /tool/netwatch/add comment="notify, name=client, resolve=client.dhcp.example.com, no-resolve-fail" host=10.0.0.0; - -### Add a note in notification - -For some extra information it is possible to add a text note. This is -included verbatim into the notification. - - /tool/netwatch/add comment="notify, name=example, note=Do not touch!" host=10.0.0.31; - -### Add a link in notification - -It is possible to add a link in notification, that is added below the -formatted notification text. - - /tool/netwatch/add comment="notify, name=example.com, resolve=example.com, link=https://example.com/" host=0.0; - -Tips & Tricks -------------- - -### One of several hosts - -Sometimes it is sufficient if one of a number of hosts is available. You can -make `netwatch-notify` check for that by adding several items with same -`name`. Note that `count` has to be multiplied to keep the actual time. - - /tool/netwatch/add comment="notify, name=service, count=10" host=10.0.0.10; - /tool/netwatch/add comment="notify, name=service, count=10" host=10.0.0.20; - -### Checking internet connectivity - -Sometimes you can not check your gateway for internet connectivity, for -example when it does not respond to pings or has a dynamic address. You could -check `1.1.1.1` (Cloudflare DNS), `9.9.9.9` (Quad-nine DNS), `8.8.8.8` -(Google DNS) or any other reliable address that indicates internet -connectivity. - - /tool/netwatch/add comment="notify, name=internet" host=1.1.1.1; - -A target like this suits well to be parent for other checks. - - /tool/netwatch/add comment="notify, name=example.com, parent=internet" host=93.184.216.34; - -### Checking specific ISP - -Having several ISPs for redundancy a failed link may go unnoticed without -proper monitoring. You can use routing-mark to monitor specific connections. -Create a route and firewall mangle rule. - - /routing/table/add fib name=via-isp1; - /ip/route/add distance=1 gateway=isp1 routing-table=via-isp1; - /ip/firewall/mangle/add action=mark-routing chain=output new-routing-mark=via-isp1 dst-address=1.0.0.1 passthrough=yes; - -Finally monitor the address with `netwatch-notify`. - - /tool/netwatch/add comment="notify, name=quad-one via isp1" host=1.0.0.1; - -Note that *all* traffic to the given address is routed that way. In case of -link failure this address is not available, so use something reliable but -non-essential. In this example the address `1.0.0.1` is used, the same service -(Cloudflare DNS) is available at `1.1.1.1`. - -### Use in combination with DNS and DoH management - -Netwatch entries can be created to work with both - this script and -[netwatch-dns](netwatch-dns.md). Just give options for both: - - /tool/netwatch/add comment="doh, notify, name=cloudflare-dns" host=1.1.1.1; - -See also --------- - -* [Manage DNS and DoH servers from netwatch](netwatch-dns.md) +Also notification settings are required for e-mail and telegram. --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/netwatch-syslog.md b/doc/netwatch-syslog.md index 6a337d4..9a28bb9 100644 --- a/doc/netwatch-syslog.md +++ b/doc/netwatch-syslog.md @@ -1,5 +1,34 @@ -This script has been dropped. Filtering in firewall is advised, which should -look something like this: +Manage remote logging +===================== - /ip/firewall/filter/add action=reject chain=output out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; - /ip/firewall/filter/add action=reject chain=forward out-interface-list=WAN port=514 protocol=udp reject-with=icmp-admin-prohibited; +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS supports sending log messages via network to a remote syslog server. +If the server is not available no log messages (with potentially sensitive +information) should be sent. This script disables remote logging by +availability. + +Requirements and installation +----------------------------- + +Let's assume there is a remote log action and associated logging rule: + + / system logging action set remote=10.0.0.1 [ find where name="remote" ]; + / system logging add action=remote topics=info; + +Just install the script: + + $ScriptInstallUpdate netwatch-syslog; + +... and create a netwatch matching the IP address from logging action above: + + / tool netwatch add down-script=netwatch-syslog host=10.0.0.1 up-script=netwatch-syslog; + +All logging rules are disabled when host is down. + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/ospf-to-leds.md b/doc/ospf-to-leds.md index 3694d35..72fab6b 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -1,17 +1,7 @@ Visualize OSPF state via LEDs ============================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -29,7 +19,7 @@ Just install the script: ... and add a scheduler to run the script periodically: - /system/scheduler/add interval=20s name=ospf-to-leds on-event="/system/script/run ospf-to-leds;" start-time=startup; + / system scheduler add interval=20s name=ospf-to-leds on-event="/ system script run ospf-to-leds;" start-time=startup; Configuration ------------- @@ -37,8 +27,8 @@ Configuration The configuration goes to OSPF instance's comment. To visualize state for instance `default` via LED `user-led` set this: - /routing/ospf/instance/set default comment="ospf-to-leds, leds=user-led"; + / routing ospf instance set default comment="ospf-to-leds, leds=user-led"; --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/packages-update.md b/doc/packages-update.md index 75225fe..882ce80 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -1,34 +1,20 @@ Manage system update ==================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- In rare cases RouterOS fails to properly downlaod package on update -(`/system/package/update/install`), resulting in borked system with missing +(`/ system package update install`), resulting in borked system with missing packages. This script tries to avoid this situation by doing some basic verification. But it provides some extra functionality: -* upload backup to Mikrotik cloud if [backup-cloud](backup-cloud.md) is - installed -* send backup via e-mail if [backup-email](backup-email.md) is installed -* save configuration to fallback partition if - [backup-partition](backup-partition.md) is installed -* upload backup to server if [backup-upload](backup-upload.md) is installed +* send backup via e-mail if [email-backup](email-backup.md) is installed +* upload backup if [upload-backup](upload-backup.md) is installed * schedule reboot at night Requirements and installation @@ -41,38 +27,20 @@ Just install the script: It is automatically run by [check-routeros-update](check-routeros-update.md) if available. -Configuration -------------- - -The configuration goes to `global-config-overlay`, this is the only parameter: - -* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM - and 5 AM) - -By modifying the scheduler's `start-time` you can force the reboot at -different time. - -> ℹ️ **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. - Usage and invocation -------------------- Alternatively run it manually: - /system/script/run packages-update; + / system script run packages-update; See also -------- -* [Upload backup to Mikrotik cloud](backup-cloud.md) -* [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](backup-partition.md) -* [Upload backup to server](backup-upload.md) * [Notify on RouterOS update](check-routeros-update.md) -* [Automatically upgrade firmware and reboot](firmware-upgrade-reboot.md) +* [Send backup via e-mail](email-backup.md) +* [Upload backup to server](upload-backup.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/ppp-on-up.md b/doc/ppp-on-up.md index 305afc1..432a640 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -1,17 +1,7 @@ Run scripts on ppp connection ============================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -31,7 +21,7 @@ Just install the script: ... and make it the `on-up` script for ppp profile: - /ppp/profile/set on-up=ppp-on-up [ find ]; + / ppp profile set on-up=ppp-on-up [ find ]; See also -------- @@ -40,5 +30,5 @@ See also * [Update tunnelbroker configuration](update-tunnelbroker.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/rotate-ntp.md b/doc/rotate-ntp.md index 9a016a3..eb04f5c 100644 --- a/doc/rotate-ntp.md +++ b/doc/rotate-ntp.md @@ -1,3 +1,40 @@ -This script has been dropped as the limitation does no longer exist with -RouterOS 7.x, where you can enable a ntp server and use a name for the client -at the same time. +Rotate NTP servers +================== + +[◀ Go back to main README](../README.md) + +Description +----------- + +RouterOS requires NTP servers to be configured by IP address. Servers from a +pool may appear and disappear, leaving broken NTP configuration. + +This script allows to rotate IP addresses from a given pool. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate rotate-ntp; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, this is the parameter: + +* `NtpPool`: dns name of ntp server pool + +Usage and invocation +-------------------- + +Just run the script to update the NTP configuration with actual IP +addresses from pool if required. + +Alternatively a scheduler can be created: + + / system scheduler add interval=5d name=rotate-ntp on-event="/ system script run rotate-ntp;" start-time=startup; + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/sms-action.md b/doc/sms-action.md index b696c85..df9e14f 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -1,17 +1,7 @@ Act on received SMS =================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -35,13 +25,9 @@ The configuration goes to `global-config-overlay`, this is the only parameter: * `SmsAction`: an array with pre-defined actions -> ℹ️ **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. - Then enable SMS actions: - /tool/sms/set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; + / tool sms set allowed-number=+491234567890 receive-enabled=yes secret=s3cr3t; Usage and invocation -------------------- @@ -59,5 +45,5 @@ See also * [Forward received SMS](sms-forward.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/sms-forward.d/notification.avif b/doc/sms-forward.d/notification.avif deleted file mode 100644 index 01eb7ba..0000000 Binary files a/doc/sms-forward.d/notification.avif and /dev/null differ diff --git a/doc/sms-forward.md b/doc/sms-forward.md index ccb6482..27c3847 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -1,17 +1,7 @@ Forward received SMS ==================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -20,10 +10,6 @@ RouterOS can receive SMS. This script forwards SMS as notification. A broadband interface with SMS support is required. -### Sample notification - -![sms-forward notification](sms-forward.d/notification.avif) - Requirements and installation ----------------------------- @@ -33,60 +19,15 @@ Just install the script: ... and add a scheduler to run it periodically: - /system/scheduler/add interval=2m name=sms-forward on-event="/system/script/run sms-forward;" start-time=startup; + / system scheduler add interval=2m name=sms-forward on-event="/ system script run sms-forward;" start-time=startup; Configuration ------------- -You have to enable receiving of SMS: +Notification settings are required for e-mail and telegram. Also you have +to enable receiving of SMS: - /tool/sms/set receive-enabled=yes; - -The configuration goes to `global-config-overlay`, this is the only parameter: - -* `SmsForwardHooks`: an array with pre-defined hooks, where each hook consists - of `match` (which is matched against the received message), `allowed-number` - (which is matched against the sending phone number or name) and `command`. - For `match` and `allowed-number` regular expressions are supported. Actual - phone number (`$Phone`) and message (`$Message`) are available for the hook. - -> ℹ️ **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. - -Notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md), -[ntfy](mod/notification-ntfy.md) and/or -[telegram](mod/notification-telegram.md). - -Tips & Tricks -------------- - -### Take care of harmful commands! - -It is easy to fake the sending phone number! So make sure you do not rely on -that number for potentially harmful commands. Add a shared secret to match -into the text instead, for example: `reboot-53cr3t-5tr1n9` instead of just -`reboot`. - -### Order new volume - -Most broadband providers include a volume limit for their data plans. The -hook functionality can be used to order new volume automatically. - -Let's assume an imaginary provider **ABC** sends a message when the available -volume is about to deplete. The message is sent from `ABC` and the text -contains the string `80%`. New volume can be ordered by sending a SMS back to -the phone number `1234` with the text `data-plan`. - - :global SmsForwardHooks { - { match="80%"; - allowed-number="ABC"; - command="/tool/sms/send lte1 phone-number=1234 message=\"data-plan\";" }; - }; - -Adjust the values to your own needs. + / tool sms set receive-enabled=yes; See also -------- @@ -94,5 +35,5 @@ See also * [Act on received SMS](sms-action.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/ssh-keys-import.md b/doc/ssh-keys-import.md index d1325aa..d221072 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -1,2 +1,33 @@ -This script has been replaced by a module. Please see -[Import ssh keys for public key authentication](mod/ssh-keys-import.md). +Import SSH keys +=============== + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script imports public SSH keys (files with extension "`pub`") into +local store for user authentication. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate ssh-keys-import; + +Usage and invocation +-------------------- + +Copy files with extension "`pub`" containing public SSH keys for your device. +Then run the script: + + / system script run ssh-keys-import; + +Starting with an `authorized_keys` file you can split it on a shell: + + while read type key name; do echo $type $key $name > $name.pub; done < authorized_keys + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index c72f220..68484dc 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -1,14 +1,7 @@ Play Super Mario theme ====================== -[![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) +[◀ Go back to main README](../README.md) Description ----------- @@ -29,10 +22,10 @@ Usage and invocation Just run the script to play: - /system/script/run super-mario-theme; + / system script run super-mario-theme; For extra fun use it for dhcp lease script. :) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/telegram-chat.d/01-chat-specific.avif b/doc/telegram-chat.d/01-chat-specific.avif deleted file mode 100644 index ab75f78..0000000 Binary files a/doc/telegram-chat.d/01-chat-specific.avif and /dev/null differ diff --git a/doc/telegram-chat.d/02-chat-all.avif b/doc/telegram-chat.d/02-chat-all.avif deleted file mode 100644 index ed1a389..0000000 Binary files a/doc/telegram-chat.d/02-chat-all.avif and /dev/null differ diff --git a/doc/telegram-chat.d/03-reply.avif b/doc/telegram-chat.d/03-reply.avif deleted file mode 100644 index 515853e..0000000 Binary files a/doc/telegram-chat.d/03-reply.avif and /dev/null differ diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md deleted file mode 100644 index 1e6f70f..0000000 --- a/doc/telegram-chat.md +++ /dev/null @@ -1,152 +0,0 @@ -Chat with your router and send commands via Telegram bot -======================================================== - -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. - -Description ------------ - -This script makes your device poll a Telegram bot for new messages. With -these messages you can send commands to your device and make it run them. -The resulting output is send back to you. - -Requirements and installation ------------------------------ - -Just install the script and the module for notifications via Telegram: - - $ScriptInstallUpdate telegram-chat,mod/notification-telegram; - -Then create a schedule that runs the script periodically: - - /system/scheduler/add start-time=startup interval=30s name=telegram-chat on-event="/system/script/run telegram-chat;"; - -> ⚠️ **Warning**: Make sure to keep the interval in sync when installing -> on several devices. Differing polling intervals will result in missed -> messages. - -Configuration -------------- - -Make sure to configure -[notifications via telegram](mod/notification-telegram.md) first. The -additional configuration goes to `global-config-overlay`, these are the -parameters: - -* `TelegramChatIdsTrusted`: an array with trusted chat ids or user names -* `TelegramChatGroups`: define the groups a device should belong to - -> ℹ️ **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. - -Usage and invocation --------------------- - -### Activating device(s) - -This script is capable of chatting with multiple devices. By default a -device is passive and not acting on messages. To activate it send a message -containing `! identity` (exclamation mark, optional space and system's -identity). To query all dynamic ip addresses form a device named "*MikroTik*" -send `! MikroTik`, followed by `/ip/address/print where dynamic;`. - -![chat to specific device](telegram-chat.d/01-chat-specific.avif) - -Devices can be grouped to chat with them simultaneously. The default group -"*all*" can be activated by sending `! @all`, which will make all devices -act on your commands. - -![chat to all devices](telegram-chat.d/02-chat-all.avif) - -Send a single exclamation mark or non-existent identity to make all -devices passive again. - -### Reply to message - -Let's assume you received a message from a device before, and want to send -a command to that device. No need to activate it, you can just reply to -that message. - -![reply to message](telegram-chat.d/03-reply.avif) - -Associated messages are cleared on device reboot. - -### Ask for devices - -Send a message with a single question mark (`?`) to query for devices -currenty online. The answer can be used for command via reply then. - -Known limitations ------------------ - -### Do not use numeric ids! - -Numeric ids are valid within a session only. Usually you can use something -like this to print all ip addresses and remove the first one: - - /ip/address/print; - /ip/address/remove 0; - -This will fail when sent in separate messages. Instead you should use basic -scripting capabilities. Try to print what you want to act on... - - /ip/address/print where interface=eth; - -... verify and finally remove it. - - /ip/address/remove [ find where interface=eth ]; - -What does work is using the persistent ids: - - /ip/address/print show-ids; - -The output contains an id starting with asterisk that can be used: - - /ip/address/remove *E; - -### Mind command runtime - -The command is run in background while the script waits for it - about -20 seconds at maximum. A command exceeding that time continues to run in -background, but the output in the message is missing or truncated then. - -If you still want a response you can work around this by making your code -send information on its own. Something like this should do the job: - - :global SendTelegram; - :delay 30s; - $SendTelegram "Command finished" "Your command finished..."; - -### Output size - -Telegram messages have a limit of 4096 characters. If output is too large it -is truncated, and a warning is added to the message. - -### Sending commands to a group - -Adding a bot to a group allows it to send messages to that group. To allow -it to receive messages you have to make it an admin of that group! It is -fine to deny all permissions, though. - -Also adding an admin to a group can cause the group id to change, so check -that if notifications break suddenly. - -See also --------- - -* [Send notifications via Telegram](mod/notification-telegram.md) - ---- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) diff --git a/doc/unattended-lte-firmware-upgrade.md b/doc/unattended-lte-firmware-upgrade.md index cb96aa1..68c74a1 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -1,14 +1,7 @@ Install LTE firmware upgrade ============================ -[![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) +[◀ Go back to main README](../README.md) Description ----------- @@ -19,7 +12,6 @@ This script upgrades LTE firmware on compatible devices: * R11e-LTE-US * R11e-4G * R11e-LTE6 -* ... and more - probably what ever Mikrotik builds into their devices A temporary scheduler is created to be independent from terminal. Thus starting the upgrade process over the broadband connection is supported. @@ -27,10 +19,6 @@ starting the upgrade process over the broadband connection is supported. Requirements and installation ----------------------------- -The firmware is downloaded over the air, so a working broadband connection -on the lte interface to be updated is required! Having internet access from -different gateway is not sufficient! - Just install the script: $ScriptInstallUpdate unattended-lte-firmware-upgrade; @@ -40,7 +28,7 @@ Usage and invocation Run the script if an upgrade for your LTE hardware is available: - /system/script/run unattended-lte-firmware-upgrade; + / system script run unattended-lte-firmware-upgrade; Then be patient, go for a coffee and wait for the upgrade process to finish. @@ -50,5 +38,5 @@ See also * [Notify on LTE firmware upgrade](check-lte-firmware-upgrade.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/update-gre-address.md b/doc/update-gre-address.md index de9f622..870759e 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -1,17 +1,7 @@ Update GRE configuration with dynamic addresses =============================================== -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -33,7 +23,7 @@ Just install the script: ... and add a scheduler to run the script periodically: - /system/scheduler/add interval=30s name=update-gre-address on-event="/system/script/run update-gre-address;" start-time=startup; + / system scheduler add interval=30s name=update-gre-address on-event="/ system script run update-gre-address;" start-time=startup; Configuration ------------- @@ -41,8 +31,8 @@ Configuration The configuration goes to interface's comment. Add the client's IKEv2 certificate CN into the comment: - /interface/gre/set comment="ikev2-client1" gre-client1; + / interface gre set comment="ikev2-client1" gre-client1; --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/update-tunnelbroker.md b/doc/update-tunnelbroker.md index ee0fe98..3641588 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -1,17 +1,7 @@ Update tunnelbroker configuration ================================= -[![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) - -> ℹ️ **Info**: This script can not be used on its own but requires the base -> installation. See [main README](../README.md) for details. +[◀ Go back to main README](../README.md) Description ----------- @@ -35,10 +25,11 @@ Configuration The configuration goes to interface's comment: - /interface/6to4/set comment="tunnelbroker, user=user, id=12345, pass=s3cr3t" tunnelbroker; + / interface 6to4 set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; -You should know you user name from login. The `id` is the tunnel's numeric -id, `pass` is the *update key* found on the tunnel's advanced tab. +Also enabling dynamic DNS in Mikrotik cloud is required: + + / ip cloud set ddns-enabled=yes; See also -------- @@ -46,5 +37,5 @@ See also * [Run scripts on ppp connection](ppp-on-up.md) --- -[⬅️ Go back to main README](../README.md) -[⬆️ Go back to top](#top) +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/doc/upload-backup.md b/doc/upload-backup.md index 83c9991..bbfbcc4 100644 --- a/doc/upload-backup.md +++ b/doc/upload-backup.md @@ -1 +1,62 @@ -This script has been renamed. Please see [backup-upload](backup-upload.md). +Upload backup to server +======================= + +[◀ Go back to main README](../README.md) + +Description +----------- + +This script uploads binary backup (`/ system backup save`) and complete +configuration export (`/ export terse`) to external server. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate upload-backup; + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `BackupSendBinary`: whether to send binary backup +* `BackupSendExport`: whether to send configuration export +* `BackupPassword`: password to encrypt the backup with +* `BackupUploadUrl`: url to upload to +* `BackupUploadUser`: username for server authentication +* `BackupUploadPass`: password for server authentication + +Also notification settings are required for e-mail and telegram. + +### Issues with SFTP client + +The RouterOS SFTP client is picky if it comes to authentication methods. +I had to disable all but password authentication on server side. For openssh +edit `/etc/ssh/sshd_config` and add a directive like this, changed for your +needs: + + Match User mikrotik + AuthenticationMethods password + +Usage and invocation +-------------------- + +Just run the script: + + / system script run upload-backup; + +Creating a scheduler may be an option: + + / system scheduler add interval=1w name=upload-backup on-event="/ system script run upload-backup;" start-time=09:25:00; + +See also +-------- + +* [Send backup via e-mail](email-backup.md) +* [Upload backup to Mikrotik cloud](cloud-backup.md) + +--- +[◀ Go back to main README](../README.md) +[▲ Go back to top](#top) diff --git a/early-errors b/early-errors new file mode 100644 index 0000000..e6160e8 --- /dev/null +++ b/early-errors @@ -0,0 +1,6 @@ +#!rsc by RouterOS +# RouterOS script: early-errors + +:global LogPrintExit; + +$LogPrintExit warning ("This script has been replaced. Please migrate to 'log-forward'.") true; diff --git a/email-backup b/email-backup new file mode 100644 index 0000000..4c7d1a4 --- /dev/null +++ b/email-backup @@ -0,0 +1,57 @@ +#!rsc by RouterOS +# RouterOS script: email-backup +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# create and email backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md + +:global BackupPassword; +:global BackupSendBinary; +:global BackupSendExport; +:global Domain; +:global EmailBackupCc; +:global EmailBackupTo; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global LogPrintExit; +:global WaitForFile; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit error ("Configured to send neither backup nor config export.") true; +} + +# filename based on identity +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local BackupFile "none"; +:local ConfigFile "none"; +:local Attach [ :toarray "" ]; + +# binary backup +:if ($BackupSendBinary = true) do={ + / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; + $WaitForFile ($FileName . ".backup"); + :set BackupFile ($FileName . ".backup"); + :set Attach ($Attach, $BackupFile); +} + +# create configuration export +:if ($BackupSendExport = true) do={ + / export terse file=$FileName; + $WaitForFile ($FileName . ".rsc"); + :set ConfigFile ($FileName . ".rsc"); + :set Attach ($Attach, $ConfigFile); +} + +# send email with status and files +/ tool e-mail send to=$EmailBackupTo cc=$EmailBackupCc \ + subject=("[" . $Identity . "] Backup & Config") \ + body=("See attached files for backup and config export for " . \ + $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile) \ + file=$Attach; diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc deleted file mode 100644 index 86a9a8c..0000000 --- a/firmware-upgrade-reboot.rsc +++ /dev/null @@ -1,60 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# install firmware upgrade, and reboot -# https://rsc.eworm.de/doc/firmware-upgrade-reboot.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ScriptLock; - :global VersionToNum; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local RouterBoard [ /system/routerboard/get ]; - :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $LogPrint info $ScriptName ("Current and upgrade firmware match with version " . \ - $RouterBoard->"current-firmware" . "."); - :set ExitOK true; - :error true; - } - :if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ - $LogPrint info $ScriptName ("Different firmware version is available, but it is a downgrade. Ignoring."); - :set ExitOK true; - :error true; - } - - :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ - $LogPrint info $ScriptName ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ - " is available, upgrading."); - /system/routerboard/upgrade; - } - - :while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ - message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ - :delay 1s; - } - - :local Uptime [ /system/resource/get uptime ]; - :if ($Uptime < 1m) do={ - :delay $Uptime; - } - - $LogPrint info $ScriptName ("Firmware upgrade successful, rebooting."); - /system/reboot; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/fw-addr-lists.d/allow b/fw-addr-lists.d/allow deleted file mode 100644 index 8b59ed7..0000000 --- a/fw-addr-lists.d/allow +++ /dev/null @@ -1,3 +0,0 @@ -# an ip address list for use with fw-addr-lists script -# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md -git.eworm.de diff --git a/fw-addr-lists.d/block b/fw-addr-lists.d/block deleted file mode 100644 index 5e9fef2..0000000 --- a/fw-addr-lists.d/block +++ /dev/null @@ -1,5 +0,0 @@ -# an ip address list for use with fw-addr-lists script -# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md - -# example.net -93.184.216.34 diff --git a/fw-addr-lists.d/mikrotik b/fw-addr-lists.d/mikrotik deleted file mode 100644 index 3b31a94..0000000 --- a/fw-addr-lists.d/mikrotik +++ /dev/null @@ -1,5 +0,0 @@ -# AS51894 Mikrotikls SIA -# https://bgp.he.net/AS51894 -159.148.147.0/24 -159.148.172.0/24 -2a02:610:7501::/48 diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc deleted file mode 100644 index f0940fe..0000000 --- a/fw-addr-lists.rsc +++ /dev/null @@ -1,214 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: fw-addr-lists -# Copyright (c) 2023-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.16 -# -# download, import and update firewall address-lists -# https://rsc.eworm.de/doc/fw-addr-lists.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global FwAddrLists; - :global FwAddrListTimeOut; - - :global CertificateAvailable; - :global EitherOr; - :global FetchHuge; - :global HumanReadableNum; - :global LogPrint; - :global LogPrintOnce; - :global LogPrintVerbose; - :global ScriptLock; - :global WaitFullyConnected; - - :local FindDelim do={ - :local ValidChars "0123456789.:/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; - :for I from=0 to=[ :len $1 ] do={ - :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ - :return $I; - } - } - } - - :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; - } - $WaitFullyConnected; - - :local ListComment ("managed by " . $ScriptName); - - :foreach FwListName,FwList in=$FwAddrLists do={ - :local CntAdd 0; - :local CntRenew 0; - :local CntRemove 0; - :local IPv4Addresses ({}); - :local IPv6Addresses ({}); - :local Failure false; - - :foreach List in=$FwList do={ - :local CheckCertificate false; - :local Data false; - :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; - - :if ([ :len ($List->"cert") ] > 0) do={ - :set CheckCertificate true; - :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ - $LogPrint warning $ScriptName ("Downloading required certificate (" . $FwListName . \ - " / " . $List->"url" . ") failed, trying anyway."); - } - } - - :for I from=1 to=5 do={ - :if ($Data = false) do={ - :set Data [ :tolf [ $FetchHuge $ScriptName ($List->"url") $CheckCertificate ] ]; - :if ($Data = false) do={ - :if ($I < 5) do={ - $LogPrint debug $ScriptName ("Failed downloading for list '" . $FwListName . \ - "', " . $I . ". try from: " . $List->"url"); - :delay (($I * $I) . "s"); - } - } - } - } - - :if ($Data = false) do={ - :set Data ""; - :set Failure true; - $LogPrint warning $ScriptName ("Failed downloading for list '" . $FwListName . \ - "' from: " . $List->"url"); - } else={ - $LogPrint debug $ScriptName ("Downloaded " . [ $HumanReadableNum [ :len $Data ] 1024 ] . \ - "B for list '" . $FwListName . "' from: " . $List->"url"); - } - - :foreach Line in=[ :deserialize $Data delimiter="\n" from=dsv options=dsv.plain ] do={ - :set Line ($Line->0); - :local Address; - :if ([ :pick $Line 0 1 ] = "{") do={ - :do { - :set Address [ :tostr ([ :deserialize from=json $Line ]->"cidr") ]; - } on-error={ } - } else={ - :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={ - :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={ - :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->$Branch->$Address) $TimeOut; - :set ($IPv6Addresses->$Branch->$Address) $TimeOut; - :error true; - } - } on-error={ } - } - } - - :foreach Entry in=[ /ip/firewall/address-list/find where \ - list=$FwListName comment=$ListComment ] do={ - :local Address [ /ip/firewall/address-list/get $Entry 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={ - $LogPrintVerbose debug $ScriptName ("Removing IPv4 address from list '" . $FwListName . \ - "': " . $Address); - /ip/firewall/address-list/remove $Entry; - :set CntRemove ($CntRemove + 1); - } - } - } - - :foreach Entry in=[ /ipv6/firewall/address-list/find where \ - list=$FwListName comment=$ListComment ] do={ - :local Address [ /ipv6/firewall/address-list/get $Entry 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={ - $LogPrintVerbose debug $ScriptName ("Removing IPv6 address from list '" . $FwListName . \ - "': " . $Address); - /ipv6/firewall/address-list/remove $Entry; - :set CntRemove ($CntRemove + 1); - } - } - } - - :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 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); - } - } - } - - $LogPrint info $ScriptName ("list: " . $FwListName . \ - " (" . [ $HumanReadableNum ($CntAdd + $CntRenew) 1000 ] . ")" . \ - " -- added: " . [ $HumanReadableNum $CntAdd 1000 ] . \ - " - renewed: " . [ $HumanReadableNum $CntRenew 1000 ] . \ - " - removed: " . [ $HumanReadableNum $CntRemove 1000 ]); - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/global-config b/global-config new file mode 100644 index 0000000..b8bdd44 --- /dev/null +++ b/global-config @@ -0,0 +1,155 @@ +#!rsc by RouterOS +# RouterOS script: global-config +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# global configuration +# https://git.eworm.de/cgit/routeros-scripts/about/ + +# Make sure all configuration properties are up to date and this +# value is in sync with value in script 'global-functions'! +:global GlobalConfigVersion 42; + +# This is used for DNS and backup file. +:global Domain "example.com"; +:global HostNameInZone true; +:global PrefixInZone true; +:global ServerNameInZone false; + +# These addresses are used to send e-mails to. The to-address needs +# to be filled; cc-address can be empty, one address or a comma +# separated list of addresses. +:global EmailGeneralTo ""; +:global EmailGeneralCc ""; +#:global EmailGeneralTo "mail@example.com"; +#:global EmailGeneralCc "another@example.com,third@example.com"; + +# You can send Telegram notifications. Register a bot +# and add the token and chat ids here. +:global TelegramTokenId ""; +:global TelegramChatId ""; +#:global TelegramTokenId "123456:ABCDEF-GHI"; +#:global TelegramChatId "12345678"; +# This is whether or not to send Telegram messages with fixed-width font. +:global TelegramFixedWidthFont true; + +# Toggle this to disable symbols in notifications. +:global NotificationsWithSymbols true; +# Toggle this to disable color output in terminal/cli. +:global TerminalColorOutput true; + +# This defines what backups to generate and what password to use. +:global BackupSendBinary false; +:global BackupSendExport true; +:global BackupPassword "v3ry-s3cr3t"; +# These addresses are used to send backup and config export files to. +:global EmailBackupTo "mail@example.com"; +:global EmailBackupCc "another@example.com"; +# These credentials are used to upload backup and config export files. +# SFTP authentication is tricky, you may have to limit authentication +# methods for your SSH server. +:global BackupUploadUrl "sftp://example.com/backup/"; +:global BackupUploadUser "mikrotik"; +:global BackupUploadPass "v3ry-s3cr3t"; + +# This defines a filter on log topics not to be forwarded. +:global LogForwardFilter "(debug|info)"; +# ... and the same for log message text. +:global LogForwardFilterMessage "(^\$|^Error sending e-mail <.* Log Forwarding>:)"; +#:global LogForwardFilterMessage "(^\$|message text|...)"; + +# Specify an address to enable auto update to version assumed safe. +# The configured channel (bugfix, current, release-candidate) is appended. +:global SafeUpdateUrl ""; +#:global SafeUpdateUrl "https://example.com/ros/safe-update/"; +# Allow to install patch updates automatically. +:global SafeUpdatePatch false; +# Allow to install updates automatically if seen in neighbor list. +:global SafeUpdateNeighbor false; + +# These thresholds control when to send health notification +# on temperature and voltage. +:global CheckHealthTemperature { + temperature=50; + cpu-temperature=70; + board-temperature1=50; + board-temperature2=50; +} +# This is deviation on recovery threshold against notification flooding. +:global CheckHealthTemperatureDeviation 2; +:global CheckHealthVoltagePercent 10; + +# This controls what configuration is activated by bridge-port-to-default. +:global BridgePortTo "default"; + +# Access-list entries matching this comment are updated +# with daily pseudo-random PSK. +:global DailyPskMatchComment "Daily PSK"; +:global DailyPskSecrets { + { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; + "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; + "Evasive"; "Faded"; "Flat"; "Future"; "Grandiose"; + "Hanging"; "Humorous"; "Interesting"; "Magenta"; + "Magnificent"; "Numerous"; "Optimal"; "Pathetic"; + "Possessive"; "Remarkable"; "Rightful"; "Ruthless"; + "Stale"; "Unusual"; "Useless"; "Various" }; + { "Adhesive"; "Amusing"; "Astonishing"; "Frantic"; + "Kindhearted"; "Limping"; "Roasted"; "Robust"; + "Staking"; "Thundering"; "Ultra"; "Unreal" }; + { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; + "String"; "Whistle" } +} + +# Run different commands with multiple mode-button presses. +:global ModeButton { + 1="/ system script run leds-toggle-mode;"; + 2=":global SendNotification; :global Identity; \$SendNotification (\"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; + 3="/ system shutdown;"; + 4="/ system reboot;"; + 5="/ system script run bridge-port-toggle;"; +# add more here... +}; +# This led gives visual feedback if type is 'on' or 'off'. +:global ModeButtonLED "user-led"; + +# Run commands on SMS action. +:global SmsAction { + bridge-port-toggle="/ system script run bridge-port-toggle;"; + reboot="/ system reboot;"; + shutdown="/ system shutdown;"; +# add more here... +}; + +# This address should resolve ntp servers and is used to update +# ntp settings. A pool can rotate servers. +:global NtpPool "pool.ntp.org"; + +# This is the address used to send gps data to. +:global GpsTrackUrl "https://example.com/index.php"; + +# Enable this to fetch scripts from given url. +:global ScriptUpdatesFetch true; +:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; +#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/master/"; +#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/master/"; +:global ScriptUpdatesUrlSuffix ""; + +# This project is developed in private spare time and usage is free of charge +# for you. If you like the scripts and think this is of value for you or your +# business please consider a donation: +# https://git.eworm.de/cgit/routeros-scripts/about/#donate +# Enable this to silence donation hint. +:global IDonate false; + +# Use this for certificate auto-renew +:global CertRenewUrl ""; +#:global CertRenewUrl "https://example.com/certificates/"; +:global CertRenewTime 3w; +:global CertRenewPass { + "v3ry-s3cr3t"; + "4n0th3r-s3cr3t"; +} +:global CertIssuedExportPass { + "cert1-cn"="v3ry-s3cr3t"; + "cert2-cn"="4n0th3r-s3cr3t"; +} diff --git a/global-config-overlay b/global-config-overlay new file mode 100644 index 0000000..8925b4c --- /dev/null +++ b/global-config-overlay @@ -0,0 +1,17 @@ +#!rsc by RouterOS +# RouterOS script: global-config-overlay +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# global configuration, custom overlay +# https://git.eworm.de/cgit/routeros-scripts/about/ + +# Make sure all configuration properties are up to date and this +# value is in sync with value in script 'global-functions'! +# Comment or remove to disable change notifications. +:global GlobalConfigVersion 42; + +# Copy configuration from global-config here and modify it. + + +# End of global-config-overlay diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc deleted file mode 100644 index 9afaceb..0000000 --- a/global-config-overlay.rsc +++ /dev/null @@ -1,12 +0,0 @@ -# Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# global configuration, custom overlay -# https://rsc.eworm.de/#editing-configuration - -# Copy relevant configuration from global-config, paste and modify it here. -# https://rsc.eworm.de/global-config.rsc - - -# End of global-config-overlay diff --git a/global-config.changes b/global-config.changes new file mode 100644 index 0000000..4ad3fee --- /dev/null +++ b/global-config.changes @@ -0,0 +1,54 @@ +# RouterOS global-config changes +# Copyright (c) 2019-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md + +# Changes for global-config to be added to notification on script updates +:global GlobalConfigChanges { + 1="Moved variables from 'global-config' to 'global-functions' for independence"; + 2="Variable names became CamelCase to work around scripting issues"; + 3="Variable for certificate renew passphrase became an array to support multiple passphrases"; + 4="Added option to ignore global-config changes"; + 5="Split off new script 'cloud-backup' from 'email-backup'"; + 6="Introduced script 'upload-backup' with new configuration parameters"; + 7="Introduced script 'check-health' with new configuration parameters"; + 8="Added donation hint and option to silence it"; + 9="Introduced configuration overlay 'global-config-overlay'"; + 10="Made health threshold for voltage configurable"; + 11="Introduced function '\$ScriptInstallUpdate' to install new and update existing scripts"; + 12="Removed '\$ScriptUpdatesConfigChangesIgnore', comment '\$GlobalConfigVersion' in 'global-config-overlay' to disable change notifications"; + 13="Configuration for script 'bridge-port-to-default' changed with new syntax in comment"; + 14="Dropped script 'script-updates', use '\$ScriptInstallUpdate' exclusively!"; + 15="New documentation is online! https://git.eworm.de/cgit/routeros-scripts/about/#available-scripts"; + 16="Happy with RouterOS Scripts and have a GitHub and/or GitLab account? Please star!"; + 17="Introduced script 'early-errors'"; + 18=("Added a simple IP calculation function, try: \$IPCalc " . [ / ip address get ([ find ]->0) address ]); + 19="Commenting scripts with 'ignore', 'base-url=...' and 'url-suffix=...' is honored on update"; + 20="Added support for hooks to 'netwatch-notify'"; + 21="Added support for installing patch updates automatically by 'check-routeros-update'"; + 22="Dropped '\$ScriptUpdatesIgnore' from global configuration, auto-migrating to ignore flag in comment" + 23="Added 'log-forward' with configurable filter, which replaces 'early-errors'"; + 24="Made symbols in notifications configurable."; + 25="Added support for DHCP server name in DNS FQDN via '\$ServerNameInZone'"; + 26="Made check count threshold in 'netwatch-notify' configurable."; + 27="Added queue for Telegram notifications to resend later on error."; + 28="Made 'dhcp-to-dns' act on all bound leases, not just dynamic ones."; + 29="Added filter on log message text for 'log-forward'."; + 30="Implemented simple rate limit for 'log-forward' to prevent flooding."; + 31="Switched Telegram notifications to fixed-width font, with opt-out."; + 32="Merged mode (& reset) button scripts in single new script 'mode-button'."; + 33="Added configurable deviation on health temperature recovery threshold against notification flooding."; + 34="Introduced script 'ospf-to-leds' to visualize OSPF instance state via LEDs."; + 35="Implemented visual feedback for 'mode-button' with configurable LED."; + 36="Added support for installing updates automatically if seen in neighbor list."; + 37="Implemented simple dependency model in 'netwatch-notify'."; + 38="Imported new Let's Encrypt intermediate certificate 'R3'."; + 39="Added support for interface specific address list entries in 'ipv6-update'."; + 40="Made the certificate renewal time configurable."; + 41="Implemented migration mechanism for script updates."; + 42="Made severity in terminal output colorful, with opt-out."; +}; + +# Migration steps to be applied on script updates +:global GlobalConfigMigration { + 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; +}; diff --git a/global-config.rsc b/global-config.rsc deleted file mode 100644 index fa32b16..0000000 --- a/global-config.rsc +++ /dev/null @@ -1,271 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-config -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# global configuration -# https://rsc.eworm.de/ - -# Set this to 'true' to disable news and change notifications. -:global NoNewsAndChangesNotification false; - -# Add extra text (or emojis) in notification tags. -:global IdentityExtra ""; - -# This is used in DNS scripts ('ipsec-to-dns' and fallback in 'dhcp-to-dns') -# and backup scripts for file names. -:global Domain "example.com"; - -# You can send e-mail notifications. Configure the system's mail settings -# (/tool/e-mail), then install the module: -# $ScriptInstallUpdate mod/notification-email -# The to-address needs to be filled; cc-address can be empty, one address -# or a comma separated list of addresses. -:global EmailGeneralTo ""; -:global EmailGeneralCc ""; -#:global EmailGeneralTo "mail@example.com"; -#:global EmailGeneralCc "another@example.com,third@example.com"; - -# You can send Telegram notifications. Register a bot -# and add the token and chat ids here, then install the module: -# $ScriptInstallUpdate mod/notification-telegram -:global TelegramTokenId ""; -:global TelegramChatId ""; -#:global TelegramTokenId "123456:ABCDEF-GHI"; -#:global TelegramChatId "12345678"; -# 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 { -# "12345678"; -# "example_user"; -#}; -:global TelegramChatGroups "(all)"; -#:global TelegramChatGroups "(all|home|office)"; - -# You can send Matrix notifications. Configure these settings and -# install the module: -# $ScriptInstallUpdate mod/notification-matrix -:global MatrixHomeServer ""; -:global MatrixAccessToken ""; -:global MatrixRoom ""; -#:global MatrixHomeServer "matrix.org"; -#:global MatrixAccessToken "123456ABCDEFGHI..."; -#:global MatrixRoom "!example:matrix.org"; - -# You can send Ntfy notifications. Configure these settings and -# install the module: -# $ScriptInstallUpdate mod/notification-ntfy -:global NtfyServer "ntfy.sh"; -:global NtfyServerUser ""; -:global NtfyServerPass ""; -:global NtfyServerToken ""; -:global NtfyTopic ""; - -# It is possible to override e-mail, Telegram, Matrix and Ntfy setting -# for every script. This is done in arrays, where 'Override' is appended -# to the variable name, like this: -#:global EmailGeneralToOverride { -# "check-certificates"="override@example.com"; -# "backup-email"="backup@example.com"; -#} - -# Toggle this to disable symbols in notifications. -:global NotificationsWithSymbols true; -# Toggle this to disable color output in terminal/cli. -:global TerminalColorOutput true; - -# This defines what backups to generate and what password to use. -:global BackupSendBinary false; -:global BackupSendExport true; -:global BackupSendGlobalConfig true; -:global BackupPassword "v3ry-s3cr3t"; -:global BackupRandomDelay 0; -# These credentials are used to upload backup and config export files. -# SFTP authentication is tricky, you may have to limit authentication -# methods for your SSH server. -:global BackupUploadUrl "sftp://example.com/backup/"; -:global BackupUploadUser "mikrotik"; -:global BackupUploadPass "v3ry-s3cr3t"; -# Copy the RouterOS installation to backup partition before feature update. -: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"; -# cert="ISRG Root X2"; timeout=1w }; -# }; - "block"={ -# { url="https://rsc.eworm.de/main/fw-addr-lists.d/block"; -# cert="ISRG Root X2" }; - { 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"; - cert="Certum Trusted Network CA" }; -# { url="https://www.spamhaus.org/drop/drop_v4.json"; -# cert="GTS Root R4" }; -# { url="https://www.spamhaus.org/drop/drop_v6.json"; -# cert="GTS Root R4" }; - }; -# "mikrotik"={ -# { url="https://rsc.eworm.de/main/fw-addr-lists.d/mikrotik"; -# cert="ISRG Root X2"; timeout=1w }; -# }; -}; -:global FwAddrListTimeOut 1d; - -# This defines what log messages to filter or include by topic or message -# 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 "message text"; -#:global LogForwardFilterMessage "(message text|another text|...)"; -# ... and another setting with reverse logic. This includes messages even -# if filtered above. -:global LogForwardInclude ""; -:global LogForwardIncludeMessage ""; -#:global LogForwardInclude "account"; -#:global LogForwardIncludeMessage "message text"; - -# Specify an address to enable auto update to version assumed safe. -# The configured channel (bugfix, current, release-candidate) is appended. -:global SafeUpdateUrl ""; -#:global SafeUpdateUrl "https://example.com/ros/safe-update/"; -# Allow to install patch updates automatically. -:global SafeUpdatePatch false; -# Allow to install updates automatically if seen in neighbor list. -:global SafeUpdateNeighbor false; -:global SafeUpdateNeighborIdentity ""; -# Install *ALL* updates automatically! -# Set to all upper-case "Yes, please!" to enable. -:global SafeUpdateAll "no"; - -# Defer the reboot for night on automatic (non-interactive) update -:global PackagesUpdateDeferReboot false; - -# These thresholds control when to send health notification -# on temperature and voltage. -:global CheckHealthTemperature { - temperature=50; - cpu-temperature=70; - board-temperature1=50; - board-temperature2=50; -}; -# This is deviation on recovery threshold against notification flooding. -:global CheckHealthTemperatureDeviation 3; -:global CheckHealthVoltageLow 115; -:global CheckHealthVoltagePercent 10; - -# Access-list entries matching this comment are updated -# with daily pseudo-random PSK. -:global DailyPskMatchComment "Daily PSK"; -:global DailyPskQrCodeUrl "https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi"; -:global DailyPskSecrets { - { "Abusive"; "Aggressive"; "Bored"; "Chemical"; "Cold"; - "Cruel"; "Curved"; "Delightful"; "Discreet"; "Elite"; - "Evasive"; "Faded"; "Flat"; "Future"; "Grandiose"; - "Hanging"; "Humorous"; "Interesting"; "Magenta"; - "Magnificent"; "Numerous"; "Optimal"; "Pathetic"; - "Possessive"; "Remarkable"; "Rightful"; "Ruthless"; - "Stale"; "Unusual"; "Useless"; "Various" }; - { "Adhesive"; "Amusing"; "Astonishing"; "Frantic"; - "Kindhearted"; "Limping"; "Roasted"; "Robust"; - "Staking"; "Thundering"; "Ultra"; "Unreal" }; - { "Belief"; "Button"; "Curtain"; "Edge"; "Jewel"; - "String"; "Whistle" } -}; - -# Specify how to assemble DNS names in ipsec-to-dns. -:global HostNameInZone true; -:global PrefixInZone true; - -# Run different commands with multiple mode-button presses. -:global ModeButton { - 1="/system/leds/settings/set all-leds-off=(({ \"never\"=\"immediate\"; \"immediate\"=\"never\" })->[ get all-leds-off ]);"; - 2=":global Identity; :global SendNotification; :global SymbolForNotification; \$SendNotification ([ \$SymbolForNotification \"earth\" ] . \"Hello...\") (\"Hello world, \" . \$Identity . \" calling!\");"; - 3="/system/shutdown;"; - 4="/system/reboot;"; - 5=":global BridgePortVlan; \$BridgePortVlan alt;"; -# add more here... -}; -# This led gives visual feedback if type is 'on' or 'off'. -:global ModeButtonLED "user-led"; - -# Run commands on SMS action. -:global SmsAction { - bridge-port-vlan-alt=":global BridgePortVlan; \$BridgePortVlan alt;"; - reboot="/system/reboot;"; - shutdown="/system/shutdown;"; -# add more here... -}; - -# Run commands by hooking into SMS forward. -:global SmsForwardHooks { - { match="magic string"; - allowed-number="12345678"; - command="/system/script/run ..." }; -# add more here... -}; - -# This is the address used to send gps data to. -:global GpsTrackUrl "https://example.com/index.php"; - -# This is the base url to fetch scripts from. -:global ScriptUpdatesBaseUrl "https://rsc.eworm.de/main/"; -# alternative urls - main: stable code - next: currently in development -#:global ScriptUpdatesBaseUrl "https://rsc.eworm.de/next/"; -#:global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; -#:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/next/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/main/"; -#:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; -:global ScriptUpdatesUrlSuffix ""; -# use next branch with my git url (git.eworm.de) -#:global ScriptUpdatesUrlSuffix "?h=next"; - -# Use this for defaults with $ScriptRunOnce -# Install module with: -# $ScriptInstallUpdate mod/scriptrunonce -:global ScriptRunOnceBaseUrl ""; -:global ScriptRunOnceUrlSuffix ""; - -# This project is developed in private spare time and usage is free of charge -# for you. If you like the scripts and think this is of value for you or your -# business please consider a donation: -# https://rsc.eworm.de/#donate -# Enable this to silence donation hint. -:global IDonate false; - -# Use this for certificate auto-renew -:global CertRenewUrl ""; -#:global CertRenewUrl "https://example.com/certificates/"; -:global CertRenewTime 3w; -:global CertRenewPass { - "v3ry-s3cr3t"; - "4n0th3r-s3cr3t"; -}; -:global CertWarnTime 2w; -:global CertIssuedExportPass { - "cert1-cn"="v3ry-s3cr3t"; - "cert2-cn"="4n0th3r-s3cr3t"; -}; - -# load custom settings from overlay and snippets -# Warning: Do *NOT* copy this code to overlay! -:foreach Script in=([ /system/script/find where name="global-config-overlay" ], \ - [ /system/script/find where name~"^global-config-overlay.d/" ]) do={ - :do { - /system/script/run $Script; - } on-error={ - :log error ("Loading configuration from overlay or snippet " . \ - [ /system/script/get $Script name ] . " failed!"); - } -} diff --git a/global-functions b/global-functions new file mode 100644 index 0000000..851e632 --- /dev/null +++ b/global-functions @@ -0,0 +1,1113 @@ +#!rsc by RouterOS +# RouterOS script: global-functions +# Copyright (c) 2013-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# global functions +# https://git.eworm.de/cgit/routeros-scripts/about/ + +# expected configuration version +:global ExpectedConfigVersion 42; + +# global variables not to be changed by user +:global GlobalFunctionsReady false; +:global Identity [ / system identity get name ]; + +# global functions +:global CertificateAvailable; +:global CertificateDownload; +:global CertificateNameByCN; +:global CharacterReplace; +:global CleanFilePath; +:global DefaultRouteIsReachable; +:global DeviceInfo; +:global DNSIsResolving; +:global DownloadPackage; +:global FlushTelegramQueue; +:global GetMacVendor; +:global GetRandom20CharHex; +:global GetRandomNumber; +:global IfThenElse; +:global IPCalc; +:global LogPrintExit; +:global MailServerIsUp; +:global MkDir; +:global ParseKeyValueStore; +:global RandomDelay; +:global RequiredRouterOS; +:global ScriptFromTerminal; +:global ScriptInstallUpdate; +:global ScriptLock; +:global SendEMail; +:global SendNotification; +:global SendTelegram; +:global SymbolByUnicodeName; +:global SymbolForNotification; +:global TimeIsSync; +:global UrlEncode; +:global VersionToNum; +:global WaitDefaultRouteReachable; +:global WaitDNSResolving; +:global WaitForFile; +:global WaitFullyConnected; +:global WaitTimeSync; + +# check and download required certificate +:set CertificateAvailable do={ + :local CommonName [ :tostr $1 ]; + + :global CertificateDownload; + :global LogPrintExit; + :global ParseKeyValueStore; + :global RequiredRouterOS; + + :if ([ / system resource get free-hdd-space ] < 8388608 && \ + [ / certificate settings get crl-download ] = true && \ + [ / certificate settings get crl-store ] = "system") do={ + $LogPrintExit warning ("This system has low free flash space but " . \ + "is configured to download certificate CRLs to system!") false; + } + + :if ([ :len [ / certificate find where common-name=$CommonName ] ] = 0) do={ + $LogPrintExit info ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } + } + + :if ([ $RequiredRouterOS ("\$CertificateAvailable") "6.47" ] = false) do={ + :return true; + } + + :local CertVal [ / certificate get [ find where common-name=$CommonName ] ]; + :do { + :if ([ :len [ / certificate find where skid=($CertVal->"akid") ] ] = 0) do={ + $LogPrintExit info ("Certificate chain for \"" . $CommonName . \ + "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; + :if ([ $CertificateDownload $CommonName ] = false) do={ + :return false; + } + } + :set CertVal [ / certificate get [ find where skid=($CertVal->"akid") ] ]; + } while=(($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")); + :return true; +} + +# download and import certificate +:set CertificateDownload do={ + :local CommonName [ :tostr $1 ]; + + :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesUrlSuffix; + + :global CertificateNameByCN; + :global LogPrintExit; + :global UrlEncode; + :global WaitForFile; + + $LogPrintExit info ("Downloading and importing certificate with " . \ + "CommonName \"" . $CommonName . "\".") false; + :do { + :local LocalFileName ($CommonName . ".pem"); + :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); + / tool fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . "certs/" . \ + $UrlFileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$LocalFileName; + $WaitForFile $LocalFileName; + / certificate import file-name=$LocalFileName passphrase=""; + / file remove $LocalFileName; + + :foreach Cert in=[ / certificate find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + $CertificateNameByCN [ / certificate get $Cert common-name ]; + } + } on-error={ + $LogPrintExit warning ("Failed importing certificate with " . \ + "CommonName \"" . $CommonName . "\"!") false; + :return false; + } + :return true; +} + +# name a certificate by its common-name +:set CertificateNameByCN do={ + :local CommonName [ :tostr $1 ]; + + :global CharacterReplace; + + :local Cert [ / certificate find where common-name=$CommonName ]; + / certificate set $Cert \ + name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $CommonName "'" "-" ] " " "-" ] "---" "-" ]; +} + +# character replace +:set CharacterReplace do={ + :local String [ :tostr $1 ]; + :local ReplaceFrom [ :tostr $2 ]; + :local ReplaceWith [ :tostr $3 ]; + :local Return ""; + + :if ($ReplaceFrom = "") do={ + :return $String; + } + + :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ + :local Pos [ :find $String $ReplaceFrom ]; + :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); + :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; + } + + :return ($Return . $String); +} + +# clean file path +:set CleanFilePath do={ + :local Path [ :tostr $1 ]; + + :global CharacterReplace; + + :while ($Path ~ "//") do={ + :set $Path [ $CharacterReplace $Path "//" "/" ]; + } + :if ([ :pick $Path 0 ] = "/") do={ + :set Path [ :pick $Path 1 [ :len $Path ] ]; + } + :if ([ :pick $Path ([ :len $Path ] - 1) ] = "/") do={ + :set Path [ :pick $Path 0 ([ :len $Path ] - 1) ]; + } + + :return $Path; +} + +# default route is reachable +:set DefaultRouteIsReachable do={ + :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active !blackhole !routing-mark !unreachable ] ] > 0) do={ + :return true; + } + :return false; +} + +# get readable device info +:set DeviceInfo do={ + :global ExpectedConfigVersion; + :global GlobalConfigVersion; + :global Identity; + + :global IfThenElse; + + :local Resource [ / system resource get ]; + :local RouterBoard [ / system routerboard get ]; + :local Update [ / system package update get ]; + + :return ( \ + "Hostname: " . $Identity . \ + "\nBoard name: " . $Resource->"board-name" . \ + "\nArchitecture: " . $Resource->"architecture-name" . \ + [ $IfThenElse ($RouterBoard->"routerboard" = true) \ + ("\nModel: " . $RouterBoard->"model" . \ + [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ + (" " . $RouterBoard->"revision") ] . \ + "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + "\nRouterOS:" . \ + "\n Channel: " . $Update->"channel" . \ + "\n Installed: " . $Update->"installed-version" . \ + [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ + $Update->"installed-version" != $Update->"latest-version") \ + ("\n Available: " . $Update->"latest-version") ] . \ + "\nRouterOS-Scripts Configuration Version:" . \ + "\n Current: " . $GlobalConfigVersion . \ + [ $IfThenElse ($GlobalConfigVersion != $ExpectedConfigVersion) \ + ("\n Expected: " . $ExpectedConfigVersion) ]); +} + +# check if DNS is resolving +:set DNSIsResolving do={ + :global CharacterReplace; + + :do { + :resolve "low-ttl.eworm.de"; + :return true; + } on-error={ + :return false; + } +} + +# download package from upgrade server +:set DownloadPackage do={ + :local PkgName [ :tostr $1 ]; + :local PkgVer [ :tostr $2 ]; + :local PkgArch [ :tostr $3 ]; + :local PkgDir [ :tostr $4 ]; + + :global CertificateAvailable; + :global CleanFilePath; + :global LogPrintExit; + :global WaitForFile; + + :if ([ :len $PkgName ] = 0) do={ :return false; } + :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ / system package update get installed-version ]; } + :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ / system resource get architecture-name ]; } + + :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); + :if ($PkgArch = "x86_64" || $PkgName ~ "^routeros-") do={ + :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); + } + :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; + + :if ([ :len [ / file find where name=$PkgDest type="package" ] ] > 0) do={ + $LogPrintExit info ("Package file alreasy exists.") false; + :return true; + } + + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit error ("Downloading required certificate failed.") true; + } + + :local Retry 3; + :while ($Retry > 0) do={ + :do { + / tool fetch check-certificate=yes-without-crl \ + ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile) \ + dst-path=$PkgDest; + $WaitForFile $PkgDest; + + :if ([ / file get [ find where name=$PkgDest ] type ] = "package") do={ + :return true; + } + } on-error={ + $LogPrintExit debug ("Downloading package failed.") false; + } + + / file remove [ find where name=$PkgDest ]; + :set Retry ($Retry - 1); + } + + :return false; +} + +# flush telegram queue +:set FlushTelegramQueue do={ + :global TelegramQueue; + :global TelegramTokenId; + + :global LogPrintExit; + + :local AllDone true; + :local QueueLen [ :len $TelegramQueue ]; + + :if ([ :len [ / system scheduler find where name="FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ + $LogPrintExit warning ("Flushing Telegram messages from scheduler, but queue is empty.") false; + } + + :foreach Id,Message in=$TelegramQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :do { + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + http-data=("chat_id=" . ($Message->"chatid") . \ + "&disable_notification=" . ($Message->"silent") . \ + "&parse_mode=" . ($Message->"parsemode") . "&text=" . ($Message->"text")); + :set ($TelegramQueue->$Id); + } on-error={ + $LogPrintExit debug ("Sending queued Telegram message failed.") false; + :set AllDone false; + } + } + } + + :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ + / system scheduler remove [ find where name="FlushTelegramQueue" ]; + :set TelegramQueue; + } +} + +# get MAC vendor +:set GetMacVendor do={ + :local Mac [ :tostr $1 ]; + + :global CertificateAvailable; + :global LogPrintExit; + + :do { + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit warning ("Downloading required certificate failed.") true; + } + :local Vendor ([ / tool fetch check-certificate=yes-without-crl \ + ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); + :return $Vendor; + } on-error={ + :return "unknown vendor"; + } +} + +# generate random 20 chars hex (0-9 and a-f) +:set GetRandom20CharHex do={ + :local Random ([ / certificate scep-server otp generate minutes-valid=0 as-value ]->"password"); + / certificate scep-server otp remove [ find where password=$Random ]; + :return $Random; +} + +# generate random number +:set GetRandomNumber do={ + :local Max 4294967295; + :if ([ :typeof $1 ] != "nothing" ) do={ + :set Max ([ :tonum $1 ] + 1); + } + + :global GetRandom20CharHex; + + :local Num; + :local 40CharHex ([ $GetRandom20CharHex ] . [ $GetRandom20CharHex ]); + + :for I from=0 to=39 do={ + :local Char [ :pick $40CharHex $I ]; + :if ($Char~"[0-9]") do={ + :set Num ($Num . $Char); + } + } + + :return ([ :tonum [ :pick $Num 0 18 ] ] % $Max); +} + +# mimic conditional/ternary operator (condition ? consequent : alternative) +:set IfThenElse do={ + :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ + :return $2; + } + :return $3; +} + +# calculate and print netmask, network, min host, max host and broadcast +:set IPCalc do={ + :local Input [ :tostr $1 ]; + :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; + :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; + :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); + + :local Return { + "address"=$Address; + "netmask"=$Mask; + "networkaddress"=($Address & $Mask); + "networkbits"=$Bits; + "network"=(($Address & $Mask) . "/" . $Bits); + "hostmin"=(($Address & $Mask) | 0.0.0.1); + "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); + "broadcast"=($Address | ~$Mask); + } + + :put ( \ + "Address: " . $Return->"address" . "\n\r" . \ + "Netmask: " . $Return->"netmask" . "\n\r" . \ + "Network: " . $Return->"network" . "\n\r" . \ + "HostMin: " . $Return->"hostmin" . "\n\r" . \ + "HostMax: " . $Return->"hostmax" . "\n\r" . \ + "Broadcast: " . $Return->"broadcast"); + + :return $Return; +} + +# log and print with same text, optionally exit +:set LogPrintExit do={ + :local Severity [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Exit [ :tostr $3 ]; + + :global PrintDebug; + + :local PrintSeverity do={ + :global TerminalColorOutput; + + :if ($TerminalColorOutput != true) do={ + :return $1; + } + + :local Color { debug=96; info=97; warning=93; error=91 }; + :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); + } + + :if ($Severity ~ "^(debug|error|info)\$") do={ + :if ($Severity = "debug") do={ :log debug $Message; } + :if ($Severity = "error") do={ :log error $Message; } + :if ($Severity = "info" ) do={ :log info $Message; } + } else={ + :log warning $Message; + :set Severity "warning"; + } + + :if ($Severity != "debug" || $PrintDebug = true) do={ + :if ($Exit = "true") do={ + :error ([ $PrintSeverity $Severity ] . ": " . $Message); + } else={ + :put ([ $PrintSeverity $Severity ] . ": " . $Message); + } + } +} + +# check if mail server is up +:set MailServerIsUp do={ + :local MailServer [ / tool e-mail get address ]; + + :global EmailGeneralTo; + + :global LogPrintExit; + + :if ([ :len $EmailGeneralTo ] = 0) do={ + :return true; + } else={ + :if ($MailServer = "0.0.0.0") do={ + $LogPrintExit info ("No mail server is configured! Returning gracefully...") false; + :return true; + } + } + + :if ([ :len [ / tool netwatch find where comment=$MailServer ] ] = 0) do={ + $LogPrintExit info ("Adding netwatch entry for mail server.") false; + :local MailHost $MailServer; + :if ([ :typeof [ :toip $MailHost ] ] != "ip" ) do={ + :do { + :set MailHost [ :resolve $MailServer ]; + } on-error={ + $LogPrintExit warning ("Resolving mail server failed.") false; + :return false; + } + } + / tool netwatch add comment=$MailServer host=$MailHost; + } + + :local NetWatch [ / tool netwatch find where comment=$MailServer ]; + :local NetWatchVal [ / tool netwatch get $NetWatch ]; + :if ($NetWatchVal->"status" = "up") do={ + :return true; + } + + / tool netwatch set interval=($NetWatchVal->"interval") $NetWatch; + :delay ($NetWatchVal->"timeout"); + :if ([ / tool netwatch get $NetWatch status ] = "up") do={ + :return true; + } + + :return false; +} + +# create directory +:set MkDir do={ + :local Dir [ :tostr $1 ]; + + :global CleanFilePath; + :global WaitForFile; + + :set Dir [ $CleanFilePath $Dir ]; + + :if ([ :len [ / file find where name=$Dir type="directory" ] ] = 1) do={ + :return true; + } + + :local Return true; + :local WwwVal [ / ip service get www ]; + / ip service set www address=127.0.0.1/32 disabled=no port=80; + :do { + / tool fetch http://127.0.0.1/ dst-path=($Dir . "/tmp"); + $WaitForFile ($Dir . "/tmp"); + / file remove ($Dir . "/tmp"); + } on-error={ + :set Return false; + } + / ip service set www address=($WwwVal->"address") \ + disabled=($WwwVal->"disabled") port=($WwwVal->"port"); + :return $Return; +} + +# parse key value store +:set ParseKeyValueStore do={ + :local Source $1; + :if ([ :typeof $Source ] != "array") do={ + :set Source [ :tostr $1 ]; + } + :local Result [ :toarray "" ]; + :foreach KeyValue in=[ :toarray $Source ] do={ + :if ([ :find $KeyValue "=" ]) do={ + :set ($Result->[ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]) \ + [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; + } else={ + :set ($Result->$KeyValue) true; + } + } + :return $Result; +} + +# delay a random amount of seconds +:set RandomDelay do={ + :global GetRandomNumber; + + :delay ([ $GetRandomNumber $1 ] . "s"); +} + +# check for required RouterOS version +:set RequiredRouterOS do={ + :local Caller [ :tostr $1 ]; + :local Required [ :tostr $2 ]; + + :global IfThenElse; + :global LogPrintExit; + :global VersionToNum; + + :if ([ $VersionToNum $Required ] > [ $VersionToNum [ / system package update get installed-version ] ]) do={ + $LogPrintExit warning ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = "\$") "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + :return false; + } + :return true; +} + +# check if script is run from terminal +:set ScriptFromTerminal do={ + :local Script [ :tostr $1 ]; + + :global LogPrintExit; + + :foreach Job in=[ / system script job find where script=$Script ] do={ + :set Job [ / system script job get $Job ]; + :while ([ :typeof ($Job->"parent") ] = "id") do={ + :set Job [ / system script job get [ find where .id=($Job->"parent") ] ]; + } + :if (($Job->"type") = "login") do={ + $LogPrintExit debug ("Script " . $Script . " started from terminal.") false; + :return true; + } + } + $LogPrintExit debug ("Script " . $Script . " NOT started from terminal.") false; + + :return false; +} + +# install new scripts, update existing scripts +:set ScriptInstallUpdate do={ + :local Scripts [ :toarray $1 ]; + + :global ExpectedConfigVersion; + :global GlobalConfigVersion; + :global Identity; + :global IDonate; + :global ScriptUpdatesBaseUrl; + :global ScriptUpdatesFetch; + :global ScriptUpdatesUrlSuffix; + :global SentConfigChangesNotification; + + :global CertificateAvailable; + :global LogPrintExit; + :global ParseKeyValueStore; + :global SendNotification; + :global SymbolForNotification; + + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrintExit warning ("Downloading certificate failed, trying without.") false; + } + + :foreach Script in=$Scripts do={ + :if ([ :len [ / system script find where name=$Script ] ] = 0) do={ + $LogPrintExit info ("Adding new script: " . $Script) false; + / system script add name=$Script source="#!rsc by RouterOS\n"; + } + } + + :local ScriptInstallUpdateBefore $ScriptInstallUpdate; + + :foreach Script in=[ / system script find where source~"^#!rsc( by RouterOS)\?\n" ] do={ + :local ScriptVal [ / system script get $Script ]; + :local ScriptFile [ / file find where name=("script-updates/" . $ScriptVal->"name") ]; + :local SourceNew; + :if ([ :len $ScriptFile ] > 0) do={ + :set SourceNew [ / file get $ScriptFile content ]; + / file remove $ScriptFile; + } + + :foreach Scheduler in=[ / system scheduler find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ + :local SchedulerVal [ / system scheduler get $Scheduler ]; + :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ + $LogPrintExit warning ("Policies differ for script " . $ScriptVal->"name" . \ + " and its scheduler " . $SchedulerVal->"name" . "!") false; + } + :if ($SchedulerVal->"name" != "global-scripts" && \ + $SchedulerVal->"start-time" = "startup" && \ + $SchedulerVal->"interval" = 0s && \ + !(($SchedulerVal->"on-event") ~ "\\brun global-wait\\b")) do={ + $LogPrintExit warning ("Scheduler " . $SchedulerVal->"name" . " starts on startup, " . \ + "without waiting for global-functions. Run 'global-wait' to avoid race conditions!") false; + } + } + + :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ + :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; + :if (!($Comment->"ignore" = true)) do={ + $LogPrintExit debug ("Fetching script from url: " . $ScriptVal->"name") false; + :do { + :local BaseUrl $ScriptUpdatesBaseUrl; + :local UrlSuffix $ScriptUpdatesUrlSuffix; + :if ([ :typeof ($Comment->"base-url") ] = "str") do={ :set BaseUrl ($Comment->"base-url"); } + :if ([ :typeof ($Comment->"url-suffix") ] = "str") do={ :set UrlSuffix ($Comment->"url-suffix"); } + + :local Result [ / tool fetch check-certificate=yes-without-crl \ + ($BaseUrl . $ScriptVal->"name" . $UrlSuffix) output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set SourceNew ($Result->"data"); + } + } on-error={ + $LogPrintExit warning ("Failed fetching " . $ScriptVal->"name") false; + } + } + } + + :if ([ :len $SourceNew ] > 0) do={ + :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ + :if ($SourceNew != $ScriptVal->"source") do={ + :local DontRequirePermissions \ + ($SourceNew~"\n# requires: dont-require-permissions=yes\n"); + $LogPrintExit info ("Updating script: " . $ScriptVal->"name") false; + / system script set owner=($ScriptVal->"name") source=$SourceNew \ + dont-require-permissions=$DontRequirePermissions $Script; + :if ($ScriptVal->"name" = "global-config" && \ + [ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ + $LogPrintExit info ("Reloading global configuration and overlay.") false; + :do { + / system script { run global-config; run global-config-overlay; } + } on-error={ + $LogPrintExit error ("Reloading global configuration and overlay failed! Syntax error?") false; + } + } + :if ($ScriptVal->"name" = "global-functions") do={ + $LogPrintExit info ("Reloading global functions.") false; + :do { + / system script run global-functions; + } on-error={ + $LogPrintExit error ("Reloading global functions failed!") false; + } + } + } else={ + $LogPrintExit debug ("Script " . $ScriptVal->"name" . " did not change.") false; + } + } else={ + $LogPrintExit warning ("Looks like new script " . $ScriptVal->"name" . " is not valid. Ignoring!") false; + } + } else={ + $LogPrintExit debug ("No update for script " . $ScriptVal->"name" . ".") false; + } + } + + :if ($SentConfigChangesNotification!=$ExpectedConfigVersion && \ + $GlobalConfigVersion < $ExpectedConfigVersion) do={ + :global GlobalConfigChanges; + :global GlobalConfigMigration; + :local ChangeLogCode; + :local ConfigScript "global-config"; + :if ([ :len [ / system script find where name="global-config-overlay" ] ] > 0) do={ + :set ConfigScript "global-config-overlay"; + } + :local NotificationMessage ("Current configuration on " . $Identity . \ + " is out of date. Please update " . $ConfigScript . ", then increase " . \ + "\$GlobalConfigVersion (currently " . $GlobalConfigVersion . \ + ") to " . $ExpectedConfigVersion . " and re-run " . $ConfigScript . "."); + $LogPrintExit info ($NotificationMessage) false; + + $LogPrintExit debug ("Fetching changelog.") false; + :do { + :local Result [ / tool fetch check-certificate=yes-without-crl \ + ($ScriptUpdatesBaseUrl . "global-config.changes" . $ScriptUpdatesUrlSuffix) \ + output=user as-value ]; + :if ($Result->"status" = "finished") do={ + :set ChangeLogCode ($Result->"data"); + } + :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); + [ :parse $ChangeLogCode ]; + :for I from=($GlobalConfigVersion + 1) to=$ExpectedConfigVersion do={ + :set NotificationMessage ($NotificationMessage . \ + "\n * " . $GlobalConfigChanges->[ :tostr $I ]); + $LogPrintExit info ("Change: " . $GlobalConfigChanges->[ :tostr $I ]) false; + :local Migration ($GlobalConfigMigration->[ :tostr $I ]); + :if ([ :typeof $Migration ] = "str") do={ + $LogPrintExit info ("Applying migration: " . $Migration) false; + [ :parse $Migration ]; + } + } + :set GlobalConfigChanges; + :set GlobalConfigMigration; + } on-error={ + $LogPrintExit warning ("Failed fetching changes!") false; + :set NotificationMessage ($NotificationMessage . \ + "\n\nChanges are not available."); + } + + :local Link; + :if ($IDonate != true) do={ + :set NotificationMessage ($NotificationMessage . \ + "\n\n==== donation hint ====\n" . \ + "This project is developed in private spare time and usage is " . \ + "free of charge for you. If you like the scripts and think this is " . \ + "of value for you or your business please consider a donation."); + :set Link "https://git.eworm.de/cgit/routeros-scripts/about/#donate"; + } + + $SendNotification ([ $SymbolForNotification "pushpin" ] . "News and configuration changes") \ + $NotificationMessage $Link; + :set SentConfigChangesNotification $ExpectedConfigVersion; + } + + :if ($ScriptInstallUpdateBefore != $ScriptInstallUpdate) do={ + $LogPrintExit info ("This function '\$ScriptInstallUpdate' changed, you may want to re-run.") false; + } +} + +# lock script against multiple invocation +:set ScriptLock do={ + :global LogPrintExit; + + :local Script [ :tostr $1 ]; + + :if ([ :len [ / system script job find where script=$Script ] ] > 1) do={ + $LogPrintExit info ("Script " . $Script . " started more than once... Aborting.") true; + } +} + +# send notification via e-mail +:set SendEMail do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Link [ :tostr $3 ]; + :local Attach [ :tostr $4 ]; + + :global Identity; + :global EmailGeneralTo; + :global EmailGeneralCc; + + :global LogPrintExit; + :global IfThenElse; + + :if ([ :len $EmailGeneralTo ] = 0) do={ + :return false; + } + + :do { + :local Signature [ / system note get note ]; + / tool e-mail send to=$EmailGeneralTo cc=$EmailGeneralCc \ + subject=("[" . $Identity . "] " . $Subject) \ + body=($Message . \ + [ $IfThenElse ([ :len $Link ] > 0) ("\n\n" . $Link) "" ] . \ + [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]) \ + file=$Attach; + } on-error={ + $LogPrintExit warning ("Failed sending notification mail!") false; + } +} + +# send notification via e-mail and telegram +# Note that attachment is ignored for telegram, silent is ignored for e-mail! +:set SendNotification do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Link [ :tostr $3 ]; + :local Attach [ :tostr $4 ]; + :local Silent [ :tostr $5 ]; + + :global SendEMail; + :global SendTelegram; + + $SendEMail $Subject $Message $Link $Attach; + $SendTelegram $Subject $Message $Link $Silent; +} + +# send notification via telegram +:set SendTelegram do={ + :local Subject [ :tostr $1 ]; + :local Message [ :tostr $2 ]; + :local Link [ :tostr $3 ]; + :local Silent [ :tostr $4 ]; + + :global Identity; + :global TelegramChatId; + :global TelegramChatIdOverride; + :global TelegramFixedWidthFont; + :global TelegramQueue; + :global TelegramTokenId; + + :global CertificateAvailable; + :global CharacterReplace; + :global IfThenElse; + :global LogPrintExit; + :global SymbolForNotification; + :global UrlEncode; + + :local EscapeMD do={ + :global TelegramFixedWidthFont; + + :global CharacterReplace; + :global IfThenElse; + + :if ($TelegramFixedWidthFont != true) do={ + :return ($1 . [ $IfThenElse ($2 = "body") "\n" "" ]); + } + + :local Return $1; + :local Chars { + "body"={ "\\"; "`" }; + "hint"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; + "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; + } + :foreach Char in=($Chars->$2) do={ + :set Return [ $CharacterReplace $Return $Char ("\\" . $Char) ]; + } + + :if ($2 = "body") do={ + :return ("```\n" . $Return . "\n```"); + } + + :return $Return; + } + + :local ChatId $TelegramChatId; + :if ([ :len $TelegramChatIdOverride ] > 0) do={ + :set ChatId $TelegramChatIdOverride; + } + + :if ([ :len $TelegramTokenId ] = 0 || [ :len $ChatId ] = 0) do={ + :return false; + } + + :local Truncated false; + :local LenLink [ :len $Link ]; + :local Text ("[" . $Identity . "] " . $Subject . "\n\n" . $Message); + :local LenText [ :len $Text ]; + :if ($LenText > (3968 - $LenLink)) do={ + :set Text [ $EscapeMD ([ :pick $Text 0 (3840 - $LenLink) ] . "...") "body" ]; + :set Truncated true; + } else={ + :set Text [ $EscapeMD $Text "body" ]; + } + :if ($LenLink > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . [ $EscapeMD $Link "hint" ]); + } + :if ($Truncated = true) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ + [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + (($LenText - [ :len $Text ]) * 100 / $LenText) . "%!") "hint" ]); + } + :set Text [ $UrlEncode $Text ]; + :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; + + :do { + :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit warning ("Downloading required certificate failed.") true; + } + / tool fetch check-certificate=yes-without-crl output=none http-method=post \ + ("https://api.telegram.org/bot" . $TelegramTokenId . "/sendMessage") \ + http-data=("chat_id=" . $ChatId . "&disable_notification=" . $Silent . \ + "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text); + } on-error={ + $LogPrintExit info ("Failed sending telegram notification! Queuing...") false; + + :if ([ :typeof $TelegramQueue ] = "nothing") do={ + :set TelegramQueue [ :toarray "" ]; + } + :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + [ $EscapeMD ("This message was queued since " . [ / system clock get date ] . \ + " " . [ / system clock get time ] . " and may be obsolete.") "hint" ]) ]); + :set ($TelegramQueue->[ :len $TelegramQueue ]) { + chatid=$ChatId; parsemode=$ParseMode; text=$Text; silent=$Silent }; + :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;"; + } + } +} + +# return UTF-8 symbol for unicode name +:set SymbolByUnicodeName do={ + :local Symbols { + "alarm-clock"="\E2\8F\B0"; + "calendar"="\F0\9F\93\85"; + "cross-mark"="\E2\9D\8C"; + "fire"="\F0\9F\94\A5"; + "floppy-disk"="\F0\9F\92\BE"; + "high-voltage-sign"="\E2\9A\A1"; + "incoming-envelope"="\F0\9F\93\A8"; + "link"="\F0\9F\94\97"; + "lock-with-ink-pen"="\F0\9F\94\8F"; + "mobile-phone"="\F0\9F\93\B1"; + "pushpin"="\F0\9F\93\8C"; + "scissors"="\E2\9C\82"; + "sparkles"="\E2\9C\A8"; + "warning-sign"="\E2\9A\A0"; + "white-heavy-check-mark"="\E2\9C\85" + } + + :return ($Symbols->$1); +} + +# return symbol for notification +:set SymbolForNotification do={ + :global NotificationsWithSymbols; + :global SymbolByUnicodeName; + + :if ($NotificationsWithSymbols != true) do={ + :return ""; + } + :local Return ""; + :foreach Symbol in=[ :toarray $1 ] do={ + :set Return ($Return . [ $SymbolByUnicodeName $Symbol ]); + } + :return ($Return . " "); +} + +# check if system time is sync +:set TimeIsSync do={ + :global LogPrintExit; + + :if ([ / system ntp client get enabled ] = true) do={ + :do { + :if ([ / system ntp client get status ] = "synchronized") do={ + :return true; + } + } on-error={ + :if ([ :typeof [ / system ntp client get last-adjustment ] ] = "time") do={ + :return true; + } + } + :return false; + } + + :if ([ / ip cloud get ddns-enabled ] = true && [ / ip cloud get update-time ] = true) do={ + :if ([ :typeof [ / ip cloud get public-address ] ] = "ip") do={ + :return true; + } + :return false; + } + + $LogPrintExit info ("No time source configured! Returning gracefully...") false; + :return true; +} + +# url encoding +:set UrlEncode do={ + :local Input [ :tostr $1 ]; + :local Return ""; + + :if ([ :len $Input ] > 0) do={ + :local Chars "\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"; + :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; + "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; + "%3F"; "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; + "%7E" }; + + :for I from=0 to=([ :len $Input ] - 1) do={ + :local Char [ :pick $Input $I ]; + :local Replace [ :find $Chars $Char ]; + + :if ([ :len $Replace ] > 0) do={ + :set Char ($Subs->$Replace); + } + :set Return ($Return . $Char); + } + } + + :return $Return; +} + +# convert version string to numeric value +:set VersionToNum do={ + :local Input [ :tostr $1 ]; + :local Multi 0x1000000; + :local Return 0; + + :global CharacterReplace; + + :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ + "." "," ] "beta" ",beta," ] "rc" ",rc," ]; + + :foreach Value in=([ :toarray $Input ], 0) do={ + :local Num [ :tonum $Value ]; + :if ($Multi = 0x100) do={ + :if ([ :typeof $Num ] = "num") do={ + :set Return ($Return + 0xff00); + :set Multi ($Multi / 0x100); + } else={ + :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } + } + } + :if ([ :typeof $Num ] = "num") do={ :set Return ($Return + ($Value * $Multi)); } + :set Multi ($Multi / 0x100); + } + + :return $Return; +} + +# wait for default route to be reachable +:set WaitDefaultRouteReachable do={ + :global DefaultRouteIsReachable; + + :while ([ $DefaultRouteIsReachable ] = false) do={ + :delay 1s; + } +} + +# wait for DNS to resolve +:set WaitDNSResolving do={ + :global DNSIsResolving; + + :while ([ $DNSIsResolving ] = false) do={ + :delay 1s; + } +} + +# wait for file to be available +:set WaitForFile do={ + :local FileName [ :tostr $1 ]; + + :global CleanFilePath; + + :set FileName [ $CleanFilePath $FileName ]; + :local I 0; + + :while ([ :len [ / file find where name=$FileName ] ] = 0) do={ + :if ($I > 20) do={ + :return false; + } + :delay 100ms; + :set I ($I + 1); + } + :return true; +} + +# wait to be fully connected (default route is reachable, time is sync, DNS resolves) +:set WaitFullyConnected do={ + :global WaitDefaultRouteReachable; + :global WaitDNSResolving; + :global WaitTimeSync; + + $WaitDefaultRouteReachable; + $WaitTimeSync; + $WaitDNSResolving; +} + +# wait for time to become synced +:set WaitTimeSync do={ + :global LogPrintExit; + :global TimeIsSync; + + :while ([ $TimeIsSync ] = false) do={ + :if ([ :len [ / system script find where name="rotate-ntp" ] ] > 0 && \ + ([ / system resource get uptime ] % (180 * 1000000000)) = 0s) do={ + :do { + / system script run rotate-ntp; + } on-error={ + $LogPrintExit debug ("Running rotate-ntp failed.") false; + } + } + :delay 1s; + } +} + +# check for required RouterOS version +$RequiredRouterOS "global-functions" "6.47"; + +# signal we are ready +:set GlobalFunctionsReady true; diff --git a/global-functions.rsc b/global-functions.rsc deleted file mode 100644 index 8ae7bb8..0000000 --- a/global-functions.rsc +++ /dev/null @@ -1,1777 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-functions -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch, scheduler -# -# global functions -# https://rsc.eworm.de/ - -:local ScriptName [ :jobname ]; - -# 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; -:global Identity [ /system/identity/get name ]; - -# global functions -:global AlignRight; -:global CertificateAvailable; -:global CertificateDownload; -:global CertificateNameByCN; -:global CharacterMultiply; -:global CharacterReplace; -:global CleanFilePath; -:global CleanName; -:global DeviceInfo; -:global Dos2Unix; -:global DownloadPackage; -:global EitherOr; -:global EscapeForRegEx; -:global ExitError; -:global FetchHuge; -:global FetchUserAgentStr; -:global FormatLine; -:global FormatMultiLines; -:global GetMacVendor; -:global GetRandom20CharAlNum; -:global GetRandom20CharHex; -:global GetRandomNumber; -:global Grep; -:global HexToNum; -:global HumanReadableNum; -:global IfThenElse; -:global IsDefaultRouteReachable; -:global IsDNSResolving; -:global IsFullyConnected; -:global IsMacLocallyAdministered; -:global IsTimeSync; -:global LogPrint; -:global LogPrintOnce; -:global LogPrintVerbose; -:global MAX; -:global MIN; -:global MkDir; -:global NotificationFunctions; -:global ParseDate; -:global ParseKeyValueStore; -:global PrettyPrint; -:global ProtocolStrip; -:global RandomDelay; -:global RequiredRouterOS; -:global RmDir; -:global RmFile; -:global ScriptFromTerminal; -:global ScriptInstallUpdate; -:global ScriptLock; -:global SendNotification; -:global SendNotification2; -:global SymbolByUnicodeName; -:global SymbolForNotification; -:global Unix2Dos; -:global UrlEncode; -:global ValidateSyntax; -:global VersionToNum; -:global WaitDefaultRouteReachable; -:global WaitDNSResolving; -:global WaitForFile; -:global WaitFullyConnected; -:global WaitTimeSync; - -# align string to the right -:set AlignRight do={ - :local Input [ :tostr $1 ]; - :local Len [ :tonum $2 ]; - - :global CharacterMultiply; - :global EitherOr; - - :set Len [ $EitherOr $Len 8 ]; - :local Spaces [ $CharacterMultiply " " $Len ]; - - :return ([ :pick $Spaces 0 ($Len - [ :len $Input ]) ] . $Input); -} - -# check and download required certificate -:set CertificateAvailable do={ - :local CommonName [ :tostr $1 ]; - - :global CertificateDownload; - :global LogPrint; - :global ParseKeyValueStore; - - :if ([ /system/resource/get free-hdd-space ] < 8388608 && \ - [ /certificate/settings/get crl-download ] = true && \ - [ /certificate/settings/get crl-store ] = "system") do={ - $LogPrint warning $0 ("This system has low free flash space but " . \ - "is configured to download certificate CRLs to system!"); - } - - :if ([ :len $CommonName ] = 0) do={ - $LogPrint warning $0 ("No CommonName given!"); - :return false; - } - - :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - $LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available."); - :if ([ $CertificateDownload $CommonName ] = false) do={ - :return false; - } - } - - :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; - :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ - :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ - $LogPrint info $0 ("Certificate chain for '" . $CommonName . \ - "' is incomplete, missing '" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "'."); - :if ([ $CertificateDownload $CommonName ] = false) do={ - :return false; - } - } - :set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; - } - :return true; -} - -# download and import certificate -:set CertificateDownload do={ - :local CommonName [ :tostr $1 ]; - - :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesUrlSuffix; - - :global CertificateAvailable; - :global CertificateNameByCN; - :global CleanName; - :global FetchUserAgentStr; - :global LogPrint; - :global RmFile; - :global WaitForFile; - - $LogPrint info $0 ("Downloading and importing certificate with " . \ - "CommonName '" . $CommonName . "'."); - :local FileName ([ $CleanName $CommonName ] . ".pem"); - :do { - /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ - ($ScriptUpdatesBaseUrl . "certs/" . $FileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$FileName as-value; - $WaitForFile $FileName; - } on-error={ - $LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . \ - "' from repository! Trying fallback to mkcert.org..."); - :do { - :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ - $LogPrint error $0 ("Downloading required certificate failed."); - :return false; - } - /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ - "https://mkcert.org/generate/" http-data=[ :serialize to=json ({ $CommonName }) ] \ - dst-path=$FileName as-value; - $WaitForFile $FileName; - :if ([ /file/get $FileName size ] = 0) do={ - $RmFile $FileName; - :error false; - } - } on-error={ - $LogPrint warning $0 ("Failed downloading certificate with CommonName '" . $CommonName . "'!"); - :return false; - } - } - - /certificate/import file-name=$FileName passphrase="" as-value; - :delay 1s; - $RmFile $FileName; - - :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - /certificate/remove [ find where name~("^" . $FileName . "_[0-9]+\$") ]; - $LogPrint warning $0 ("Certificate with CommonName '" . $CommonName . "' still unavailable!"); - :return false; - } - - :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ - $CertificateNameByCN [ /certificate/get $Cert common-name ]; - } - :return true; -} - -# name a certificate by its common-name -:set CertificateNameByCN do={ - :local CommonName [ :tostr $1 ]; - - :global CleanName; - - :local Cert [ /certificate/find where common-name=$CommonName ]; - /certificate/set $Cert name=[ $CleanName $CommonName ]; -} - -# multiply given character(s) -:set CharacterMultiply do={ - :local Return ""; - :for I from=1 to=$2 do={ - :set Return ($Return . $1); - } - :return $Return; -} - -# character replace -:set CharacterReplace do={ - :local String [ :tostr $1 ]; - :local ReplaceFrom [ :tostr $2 ]; - :local ReplaceWith [ :tostr $3 ]; - :local Return ""; - - :if ($ReplaceFrom = "") do={ - :return $String; - } - - :while ([ :typeof [ :find $String $ReplaceFrom ] ] != "nil") do={ - :local Pos [ :find $String $ReplaceFrom ]; - :set Return ($Return . [ :pick $String 0 $Pos ] . $ReplaceWith); - :set String [ :pick $String ($Pos + [ :len $ReplaceFrom ]) [ :len $String ] ]; - } - - :return ($Return . $String); -} - -# clean file path -:set CleanFilePath do={ - :local Path [ :tostr $1 ]; - - :global CharacterReplace; - - :while ($Path ~ "//") do={ - :set $Path [ $CharacterReplace $Path "//" "/" ]; - } - :if ([ :pick $Path 0 ] = "/") do={ - :set Path [ :pick $Path 1 [ :len $Path ] ]; - } - :if ([ :pick $Path ([ :len $Path ] - 1) ] = "/") do={ - :set Path [ :pick $Path 0 ([ :len $Path ] - 1) ]; - } - - :return $Path; -} - -# clean name for DNS, file and more -:set CleanName do={ - :local Input [ :tostr $1 ]; - - :local Return ""; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :if ([ :typeof [ find "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" $Char ] ] = "nil") do={ - :do { - :if ([ :len $Return ] = 0) do={ - :error true; - } - :if ([ :pick $Return ([ :len $Return ] - 1) ] = "-") do={ - :error true; - } - :set Char "-"; - } on-error={ - :set Char ""; - } - } - :set Return ($Return . $Char); - } - :return $Return; -} - -# get readable device info -:set DeviceInfo do={ - :global CommitId; - :global CommitInfo; - :global ExpectedConfigVersion; - :global Identity; - - :global IfThenElse; - :global FormatLine; - - :local License [ /system/license/get ]; - :local Resource [ /system/resource/get ]; - :local RouterBoard; - :do { - :set RouterBoard [[ :parse "/system/routerboard/get" ]]; - } on-error={ } - :local Snmp [ /snmp/get ]; - :local Update [ /system/package/update/get ]; - - :return ( \ - [ $FormatLine "Hostname" $Identity ] . "\n" . \ - [ $IfThenElse ([ :len ($Snmp->"location") ] > 0) \ - ([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \ - [ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \ - ([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \ - "Hardware:\n" . \ - [ $FormatLine " Board" ($Resource->"board-name") ] . "\n" . \ - [ $FormatLine " Arch" ($Resource->"architecture-name") ] . "\n" . \ - [ $IfThenElse ($RouterBoard->"routerboard" = true) \ - ([ $FormatLine " Model" ($RouterBoard->"model") ] . \ - [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ - (" " . $RouterBoard->"revision") ] . "\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" && \ - $Update->"installed-version" != $Update->"latest-version") \ - ([ $FormatLine " Available" ($Update->"latest-version") ] . "\n") ] . \ - [ $IfThenElse ($RouterBoard->"routerboard" = true && \ - $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 ]); -} - -# convert line endings, DOS -> UNIX -:set Dos2Unix do={ - :return [ :tolf [ :tostr $1 ] ]; -} - -# download package from upgrade server -:set DownloadPackage do={ - :local PkgName [ :tostr $1 ]; - :local PkgVer [ :tostr $2 ]; - :local PkgArch [ :tostr $3 ]; - :local PkgDir [ :tostr $4 ]; - - :global CertificateAvailable; - :global CleanFilePath; - :global LogPrint; - :global MkDir; - :global RmFile; - :global WaitForFile; - - :if ([ :len $PkgName ] = 0) do={ :return false; } - :if ([ :len $PkgVer ] = 0) do={ :set PkgVer [ /system/package/update/get installed-version ]; } - :if ([ :len $PkgArch ] = 0) do={ :set PkgArch [ /system/resource/get architecture-name ]; } - - :if ($PkgName = "system") do={ :set PkgName "routeros"; } - - :local PkgFile ($PkgName . "-" . $PkgVer . "-" . $PkgArch . ".npk"); - :if ($PkgArch = "x86_64") do={ :set PkgFile ($PkgName . "-" . $PkgVer . ".npk"); } - :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; - - :if ([ $MkDir $PkgDir ] = false) do={ - $LogPrint warning $0 ("Failed creating directory, not downloading package."); - :return false; - } - - :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrint info $0 ("Package file " . $PkgName . " already exists."); - :return true; - } - - :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ - $LogPrint error $0 ("Downloading required certificate failed."); - :return false; - } - - :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); - $LogPrint info $0 ("Downloading package file '" . $PkgName . "'..."); - $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={ - :return true; - } - } on-error={ - $LogPrint debug $0 ("Downloading package file failed."); - } - - $RmFile $PkgDest; - :set Retry ($Retry - 1); - } - - $LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed."); - :return false; -} - -# return either first (if "true") or second -:set EitherOr do={ - :global IfThenElse; - - :if ([ :typeof $1 ] = "num") do={ - :return [ $IfThenElse ($1 != 0) $1 $2 ]; - } - :if ([ :typeof $1 ] = "time") do={ - :return [ $IfThenElse ($1 > 0s) $1 $2 ]; - } - # this works for boolean values, literal ones with parentheses - :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; -} - -# escape for regular expression -:set EscapeForRegEx do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars ("^.[]\$()|*+?{}\\"); - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :if ([ :find $Chars $Char ]) do={ - :set Char ("\\" . $Char); - } - :set Return ($Return . $Char); - } - - :return $Return; -} - -# simple macro to print error message on unintentional error -:set ExitError do={ - :local ExitOK [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - - :global IfThenElse; - :global LogPrint; - - :if ($ExitOK = "false") do={ - $LogPrint error $Name ([ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \ - "Function" "Script" ] . " '" . $Name . "' exited with error."); - } -} - -# fetch huge data to file, read in chunks -:set FetchHuge do={ - :local ScriptName [ :tostr $1 ]; - :local Url [ :tostr $2 ]; - :local CheckCert [ :tostr $3 ]; - - :global CleanName; - :global FetchUserAgentStr; - :global GetRandom20CharAlNum; - :global IfThenElse; - :global LogPrint; - :global MkDir; - :global RmDir; - :global RmFile; - :global WaitForFile; - - :set CheckCert [ $IfThenElse ($CheckCert = "false") "no" "yes-without-crl" ]; - - :local DirName ("tmpfs/" . [ $CleanName $ScriptName ]); - :if ([ $MkDir $DirName ] = false) do={ - $LogPrint error $0 ("Failed creating directory!"); - :return false; - } - - :local FileName ($DirName . "/" . [ $CleanName $0 ] . "-" . [ $GetRandom20CharAlNum ]); - :do { - /tool/fetch check-certificate=$CheckCert $Url dst-path=$FileName \ - http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) as-value; - } on-error={ - :if ([ $WaitForFile $FileName 500ms ] = true) do={ - $RmFile $FileName; - } - $LogPrint debug $0 ("Failed downloading from: " . $Url); - $RmDir $DirName; - :return false; - } - $WaitForFile $FileName; - - :local FileSize [ /file/get $FileName size ]; - :local Return ""; - :local VarSize 0; - :while ($VarSize != $FileSize) do={ - :set Return ($Return . ([ /file/read offset=$VarSize chunk-size=32768 file=$FileName as-value ]->"data")); - :set FileSize [ /file/get $FileName size ]; - :set VarSize [ :len $Return ]; - :if ($VarSize > $FileSize) do={ - :delay 100ms; - } - } - $RmDir $DirName; - :return $Return; -} - -# generate user agent string for fetch -:set FetchUserAgentStr do={ - :local Caller [ :tostr $1 ]; - - :local Resource [ /system/resource/get ]; - - :return ("User-Agent: Mikrotik/" . $Resource->"version" . " " . \ - $Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)"); -} - -# format a line for output -:set FormatLine do={ - :local Key [ :tostr $1 ]; - :local Value [ :tostr $2 ]; - :local Indent [ :tonum $3 ]; - :local Spaces; - :local Return ""; - - :global CharacterMultiply; - :global EitherOr; - - :set Indent [ $EitherOr $Indent 16 ]; - :local Spaces [ $CharacterMultiply " " $Indent ]; - - :if ([ :len $Key ] > 0) do={ :set Return ($Key . ":"); } - :if ([ :len $Key ] > ($Indent - 2)) do={ - :set Return ($Return . "\n" . [ :pick $Spaces 0 $Indent ] . $Value); - } else={ - :set Return ($Return . [ :pick $Spaces 0 ($Indent - [ :len $Return ]) ] . $Value); - } - - :return $Return; -} - -# format multiple lines for output -:set FormatMultiLines do={ - :local Key [ :tostr $1 ]; - :local Values [ :toarray $2 ]; - :local Indent [ :tonum $3 ]; - :local Return; - - :global FormatLine; - - :set Return [ $FormatLine $Key ($Values->0) $Indent ]; - :foreach Value in=[ :pick $Values 1 [ :len $Values ] ] do={ - :set Return ($Return . "\n" . [ $FormatLine "" $Value $Indent ]); - } - - :return $Return; -} - -# get MAC vendor -:set GetMacVendor do={ - :local Mac [ :tostr $1 ]; - - :global CertificateAvailable; - :global IsMacLocallyAdministered; - :global LogPrint; - - :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ - :return "locally administered"; - } - - :do { - :if ([ $CertificateAvailable "GTS Root R4" ] = false) do={ - $LogPrint warning $0 ("Downloading required certificate failed."); - :error false; - } - :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); - :return $Vendor; - } on-error={ - :do { - /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ - output=none as-value; - $LogPrint debug $0 ("The mac vendor is not known in database."); - } on-error={ - $LogPrint warning $0 ("Failed getting mac vendor."); - } - :return "unknown vendor"; - } -} - -# generate random 20 chars alphabetical (A-Z & a-z) and numerical (0-9) -:set GetRandom20CharAlNum do={ - :global EitherOr; - - :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ]; -} - -# generate random 20 chars hex (0-9 and a-f) -:set GetRandom20CharHex do={ - :global EitherOr; - - :return [ :rndstr length=[ $EitherOr [ :tonum $1 ] 20 ] from="0123456789abcdef" ]; -} - -# generate random number -:set GetRandomNumber do={ - :global EitherOr; - - :return [ :rndnum from=0 to=[ $EitherOr [ :tonum $1 ] 4294967295 ] ]; -} - -# return first line that matches a pattern -:set Grep do={ - :local Input ([ :tostr $1 ] . "\n"); - :local Pattern [ :tostr $2 ]; - - :if ([ :typeof [ :find $Input $Pattern ] ] = "nil") do={ - :return []; - } - - :do { - :local Line [ :pick $Input 0 [ :find $Input "\n" ] ]; - :if ([ :typeof [ :find $Line $Pattern ] ] = "num") do={ - :return $Line; - } - :set Input [ :pick $Input ([ :find $Input "\n" ] + 1) [ :len $Input ] ]; - } while=([ :len $Input ] > 0); - - :return []; -} - -# convert from hex (string) to num -:set HexToNum do={ - :local Input [ :tostr $1 ]; - - :global HexToNum; - - :if ([ :pick $Input 0 ] = "*") do={ - :return [ $HexToNum [ :pick $Input 1 [ :len $Input ] ] ]; - } - - :return [ :tonum ("0x" . $Input) ]; -} - -# return human readable number -:set HumanReadableNum do={ - :local Input [ :tonum $1 ]; - :local Base [ :tonum $2 ]; - - :global EitherOr; - :global IfThenElse; - - :local Prefix "kMGTPE"; - :local Pow 1; - - :set Base [ $EitherOr $Base 1024 ]; - :local Bin [ $IfThenElse ($Base = 1024) "i" "" ]; - - :if ($Input < $Base) do={ - :return $Input; - } - - :for I from=0 to=[ :len $Prefix ] do={ - :set Pow ($Pow * $Base); - :if ($Input / $Base < $Pow) do={ - :set Prefix [ :pick $Prefix $I ]; - :local Tmp1 ($Input * 100 / $Pow); - :local Tmp2 ($Tmp1 / 100); - :if ($Tmp2 >= 100) do={ - :return ($Tmp2 . $Prefix . $Bin); - } - :return ($Tmp2 . "." . \ - [ :pick $Tmp1 [ :len $Tmp2 ] ([ :len $Tmp1 ] - [ :len $Tmp2 ] + 1) ] . \ - $Prefix . $Bin); - } - } -} - -# mimic conditional/ternary operator (condition ? consequent : alternative) -:set IfThenElse do={ - :if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={ - :return $2; - } - :return $3; -} - -# check if default route is reachable -:set IsDefaultRouteReachable do={ - :if ([ :len [ /ip/route/find where dst-address=0.0.0.0/0 active routing-table=main ] ] > 0) do={ - :return true; - } - :return false; -} - -# check if DNS is resolving -:set IsDNSResolving do={ - :do { - :resolve "low-ttl.eworm.de"; - } on-error={ - :return false; - } - :return true; -} - -# check if system is is fully connected (default route reachable, DNS resolving, time sync) -:set IsFullyConnected do={ - :global IsDefaultRouteReachable; - :global IsDNSResolving; - :global IsTimeSync; - - :if ([ $IsDefaultRouteReachable ] = false) do={ - :return false; - } - :if ([ $IsDNSResolving ] = false) do={ - :return false; - } - :if ([ $IsTimeSync ] = false) do={ - :return false; - } - :return true; -} - -# check if mac address is locally administered -:set IsMacLocallyAdministered do={ - :if ([ :tonum ("0x" . [ :pick $1 0 [ :find $1 ":" ] ]) ] & 2 = 2) do={ - :return true; - } - :return false; -} - -# check if system time is sync -:set IsTimeSync do={ - :global IsTimeSyncCached; - :global IsTimeSyncResetNtp; - - :global LogPrintOnce; - - :if ($IsTimeSyncCached = true) do={ - :return true; - } - - :if ([ /system/ntp/client/get enabled ] = true) do={ - :if ([ /system/ntp/client/get status ] = "synchronized") do={ - :set IsTimeSyncCached true; - :return true; - } - - :local Uptime [ /system/resource/get uptime ]; - :if ([ :typeof $IsTimeSyncResetNtp ] = "nothing") do={ - :set IsTimeSyncResetNtp $Uptime; - } - :if ($Uptime - $IsTimeSyncResetNtp < 3m) do={ - :return false; - } - - $LogPrintOnce warning $0 ("The ntp client is configured, but did not sync."); - :set IsTimeSyncResetNtp $Uptime; - /system/ntp/client/set enabled=no; - :delay 20ms; - /system/ntp/client/set enabled=yes; - :return false; - } - - :if ([ /system/license/get ]->"level" = "free" || \ - [ /system/resource/get ]->"board-name" = "x86") do={ - $LogPrintOnce debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86."); - :return true; - } - - :if ([ /ip/cloud/get update-time ] = true) do={ - :if ([ :typeof [ /ip/cloud/get public-address ] ] = "ip") do={ - :set IsTimeSyncCached true; - :return true; - } - :return false; - } - - $LogPrintOnce debug $0 ("No time source configured! Returning gracefully..."); - :return true; -} - -# log and print with same text -:set LogPrint do={ - :local Severity [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Message [ :tostr $3 ]; - - :global PrintDebug; - :global PrintDebugOverride; - - :global EitherOr; - - :local Debug [ $EitherOr ($PrintDebugOverride->$Name) $PrintDebug ]; - - :local PrintSeverity do={ - :global TerminalColorOutput; - - :if ($TerminalColorOutput != true) do={ - :return $1; - } - - :local Color { debug=96; info=97; warning=93; error=91 }; - :return ("\1B[" . $Color->$1 . "m" . $1 . "\1B[0m"); - } - - :local Log ([ $EitherOr $Name "" ] . ": " . $Message); - :if ($Severity ~ ("^(debug|error|info)\$")) do={ - :if ($Severity = "debug") do={ :log debug $Log; } - :if ($Severity = "error") do={ :log error $Log; } - :if ($Severity = "info" ) do={ :log info $Log; } - } else={ - :log warning $Log; - :set Severity "warning"; - } - - :if ($Severity != "debug" || $Debug = true) do={ - :put ([ $PrintSeverity $Severity ] . ": " . $Message); - } -} - -# log and print, once until reboot -:set LogPrintOnce do={ - :local Severity [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Message [ :tostr $3 ]; - - :global LogPrint; - - :global LogPrintOnceMessages; - - :if ([ :typeof $LogPrintOnceMessages ] = "nothing") do={ - :set LogPrintOnceMessages ({}); - } - - :if ($LogPrintOnceMessages->$Message = 1) do={ - :return false; - } - - :if ([ :len [ /log/find where message=($Name . ": " . $Message) ] ] > 0) do={ - $LogPrint warning $0 \ - ("The message is already in log, scripting subsystem may have crashed before!"); - } - - :set ($LogPrintOnceMessages->$Message) 1; - $LogPrint $Severity $Name $Message; - :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; } - :return $2; -} - -# get min value -:set MIN do={ - :if ($1 < $2) do={ :return $1; } - :return $2; -} - -# create directory -:set MkDir do={ - :local Path [ :tostr $1 ]; - - :global CleanFilePath; - :global LogPrint; - :global RmDir; - :global WaitForFile; - - :local MkTmpfs do={ - :global LogPrint; - :global WaitForFile; - - :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ]; - :if ([ :len $TmpFs ] = 1) do={ - :if ([ /disk/get $TmpFs disabled ] = true) do={ - $LogPrint info $0 ("The tmpfs is disabled, enabling."); - /disk/enable $TmpFs; - } - :return true; - } - - $LogPrint info $0 ("Creating disk of type tmpfs."); - $RmDir "tmpfs"; - :do { - /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); - $WaitForFile "tmpfs"; - } on-error={ - $LogPrint warning $0 ("Creating disk of type tmpfs failed!"); - :return false; - } - :return true; - } - - :set Path [ $CleanFilePath $Path ]; - - :if ($Path = "") do={ - :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; - } - - :if ([ :pick $Path 0 5 ] = "tmpfs") do={ - :if ([ $MkTmpfs ] = false) do={ - :return false; - } - } - - :do { - /file/add type="directory" name=$Path; - $WaitForFile $Path; - } on-error={ - $LogPrint warning $0 ("Making directory '" . $Path . "' failed!"); - :return false; - } - - :return true; -} - -# prepare NotificationFunctions array -:if ([ :typeof $NotificationFunctions ] != "array") do={ - :set NotificationFunctions ({}); -} - -# parse the date and return a named array -:set ParseDate do={ - :local Date [ :tostr $1 ]; - - :return ({ "year"=[ :tonum [ :pick $Date 0 4 ] ]; - "month"=[ :tonum [ :pick $Date 5 7 ] ]; - "day"=[ :tonum [ :pick $Date 8 10 ] ] }); -} - -# parse key value store -:set ParseKeyValueStore do={ - :local Source $1; - - :if ([ :pick $Source 0 1 ] = "{") do={ - :do { - :return [ :deserialize from=json $Source ]; - } on-error={ } - } - - :if ([ :typeof $Source ] != "array") do={ - :set Source [ :tostr $1 ]; - } - :local Result ({}); - :foreach KeyValue in=[ :toarray $Source ] do={ - :if ([ :find $KeyValue "=" ]) do={ - :local Key [ :pick $KeyValue 0 [ :find $KeyValue "=" ] ]; - :local Value [ :pick $KeyValue ([ :find $KeyValue "=" ] + 1) [ :len $KeyValue ] ]; - :if ($Value="true") do={ :set Value true; } - :if ($Value="false") do={ :set Value false; } - :set ($Result->$Key) $Value; - } else={ - :set ($Result->$KeyValue) true; - } - } - :return $Result; -} - -# print lines with trailing carriage return -:set PrettyPrint do={ - :put [ :tocrlf [ :tostr $1 ] ]; -} - -# strip protocol from from url string -:set ProtocolStrip do={ - :local Input [ :tostr $1 ]; - - :local Pos [ :find $Input "://" ]; - :if ([ :typeof $Pos ] = "nil") do={ - :return $Input; - } - :return [ :pick $Input ($Pos + 3) [ :len $Input ] ]; -} - -# delay a random amount of seconds -:set RandomDelay do={ - :local Time [ :tonum $1 ]; - :local Unit [ :tostr $2 ]; - - :global EitherOr; - :global GetRandomNumber; - :global MAX; - - :if ($Time = 0) do={ - :return false; - } - - :delay ([ $MAX 10 [ $GetRandomNumber ([ :tonsec [ :totime ($Time . [ $EitherOr $Unit "s" ]) ] ] / 1000000) ] ] . "ms"); -} - -# check for required RouterOS version -:set RequiredRouterOS do={ - :local Caller [ :tostr $1 ]; - :local Required [ :tostr $2 ]; - :local Warn [ :tostr $3 ]; - - :global IfThenElse; - :global LogPrint; - :global VersionToNum; - - :if (!($Required ~ "^\\d+\\.\\d+((alpha|beta|rc|\\.)\\d+|)\$")) do={ - $LogPrint error $0 ("No valid RouterOS version: " . $Required); - :return false; - } - - :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ - :if ($Warn = "true") do={ - $LogPrint warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ - " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!"); - } - :return false; - } - :return true; -} - -# remove directory -:set RmDir do={ - :local DirName [ :tostr $1 ]; - - :global LogPrint; - - $LogPrint debug $0 ("Removing directory: ". $DirName); - - :if ([ :len [ /file/find where name=$DirName type!=directory ] ] > 0) do={ - $LogPrint error $0 ("Directory '" . $DirName . "' is not a directory."); - :return false; - } - - :local Dir [ /file/find where name=$DirName type=directory ]; - :if ([ :len $Dir ] = 0) do={ - $LogPrint debug $0 ("... which does not exist."); - :return true; - } - - :do { - /file/remove $Dir; - } on-error={ - $LogPrint error $0 ("Removing directory '" . $DirName . "' (" . $Dir . ") failed."); - :return false; - } - :return true; -} - -# remove file -:set RmFile do={ - :local FileName [ :tostr $1 ]; - - :global LogPrint; - - $LogPrint debug $0 ("Removing file: ". $FileName); - - :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=directory or type=disk) ]; - :if ([ :len $File ] = 0) do={ - $LogPrint debug $0 ("... which does not exist."); - :return true; - } - - :do { - /file/remove $File; - } on-error={ - $LogPrint error $0 ("Removing file '" . $FileName . "' (" . $File . ") failed."); - :return false; - } - :return true; -} - -# check if script is run from terminal -:set ScriptFromTerminal do={ - :local Script [ :tostr $1 ]; - - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $Script ] = false) do={ - :return false; - } - - :foreach Job in=[ /system/script/job/find where script=$Script ] do={ - :set Job [ /system/script/job/get $Job ]; - :while ([ :typeof ($Job->"parent") ] = "id") do={ - :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; - } - :if (($Job->"type") = "login") do={ - $LogPrint debug $0 ("Script " . $Script . " started from terminal."); - :return true; - } - } - - $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal."); - :return false; -} - -# install new scripts, update existing scripts -:set ScriptInstallUpdate do={ :do { - :local Scripts [ :toarray $1 ]; - :local NewComment [ :tostr $2 ]; - - :global CommitId; - :global CommitInfo; - :global ExpectedConfigVersion; - :global Identity; - :global IDonate; - :global NoNewsAndChangesNotification; - :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesCRLF; - :global ScriptUpdatesUrlSuffix; - - :global CertificateAvailable; - :global EitherOr; - :global FetchUserAgentStr; - :global Grep; - :global IfThenElse; - :global LogPrint; - :global LogPrintOnce; - :global ParseKeyValueStore; - :global RequiredRouterOS; - :global SendNotification2; - :global SymbolForNotification; - :global ValidateSyntax; - - :if ([ $CertificateAvailable "ISRG Root X2" ] = false) do={ - $LogPrint warning $0 ("Downloading certificate failed, trying without."); - } - - :foreach Script in=$Scripts do={ - :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrint info $0 ("Adding new script: " . $Script); - /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; - } - } - - :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") ]; - :local SourceNew; - - :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ - :local SchedulerVal [ /system/scheduler/get $Scheduler ]; - :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ - $LogPrint warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ - "' and its scheduler '" . $SchedulerVal->"name" . "'!"); - } - } - - :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 ]; - :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); - $LogPrint debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url); - :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set SourceNew [ :tolf ($Result->"data") ]; - } - } on-error={ - :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ - $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ - "', removing dummy. Typo on installation?"); - /system/script/remove $Script; - } else={ - $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!"); - } - :error false; - } - - :if ([ :len $SourceNew ] = 0) do={ - $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); - :error false; - } - - :local SourceCRLF [ :tocrlf $SourceNew ]; - :if ($SourceNew = $ScriptVal->"source" || $SourceCRLF = $ScriptVal->"source") do={ - $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change."); - :error false; - } - - :if ([ :pick $SourceNew 0 18 ] != "#!rsc by RouterOS\n") do={ - $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ - "' is not valid (missing shebang). Ignoring!"); - :error false; - } - - :local RequiredROS ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); - :if ([ $RequiredRouterOS $0 [ $EitherOr $RequiredROS "0.0" ] false ] = false) do={ - $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ - $RequiredROS . ", which is not met by your installation. Ignoring!"); - :error false; - } - - :local RequiredDM [ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires device-mode, ") ] ]; - :local MissingDM ({}); - :foreach Feature,Value in=$RequiredDM do={ - :if ([ :typeof ($DeviceMode->$Feature) ] = "bool" && ($DeviceMode->$Feature) = false) do={ - :set MissingDM ($MissingDM, $Feature); - } - } - :if ([ :len $MissingDM ] > 0) do={ - $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires disabled " . \ - "device-mode features (" . [ :tostr $MissingDM ] . "). Ignoring!"); - :error false; - } - - :if ([ $ValidateSyntax $SourceNew ] = false) do={ - $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . "' failed! Ignoring!"); - :error false; - } - - $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); - /system/script/set owner=($ScriptVal->"name") \ - source=[ $IfThenElse ($ScriptUpdatesCRLF = true) $SourceCRLF $SourceNew ] $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; - } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; - } - } on-error={ } - } - - :if ($ReloadGlobalFunctions = true) do={ - $LogPrint info $0 ("Reloading global functions."); - :do { - /system/script/run global-functions; - } on-error={ - $LogPrint error $0 ("Reloading global functions failed!"); - } - } - - :if ($ReloadGlobalConfig = true) do={ - $LogPrint info $0 ("Reloading global configuration."); - :do { - /system/script/run global-config; - } on-error={ - $LogPrint error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay?"); - } - } - - :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 . \ - ". Installed an older version?"); - } - - :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ - :global GlobalConfigChanges; - :global GlobalConfigMigration; - :local ChangeLogCode; - - :do { - :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); - $LogPrint debug $0 ("Fetching news, changes and migration: " . $Url); - :local Result [ /tool/fetch check-certificate=yes-without-crl \ - http-header-field=({ [ $FetchUserAgentStr $0 ] }) $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set ChangeLogCode ($Result->"data"); - } - } on-error={ - $LogPrint warning $0 ("Failed fetching news, changes and migration!"); - } - - :if ([ :len $ChangeLogCode ] > 0) do={ - :if ([ $ValidateSyntax $ChangeLogCode ] = true) do={ - :do { - [ :parse $ChangeLogCode ]; - } on-error={ - $LogPrint warning $0 ("The changelog failed to run!"); - } - } else={ - $LogPrint warning $0 ("The changelog failed syntax validation!"); - } - } - - :if ([ :len $GlobalConfigMigration ] > 0) do={ - :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ - :local Migration ($GlobalConfigMigration->[ :tostr $I ]); - :do { - :if ([ :typeof $Migration ] != "str") do={ - $LogPrint debug $0 ("Migration code for change " . $I . " is not available."); - :error false; - } - - :if ([ $ValidateSyntax $Migration ] = false) do={ - $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!"); - :error false; - } - - $LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration); - :do { - [ :parse $Migration ]; - } on-error={ - $LogPrint warning $0 ("Migration code for change " . $I . " failed to run!"); - } - } on-error={ } - } - } - - :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ - "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ - "Please review and update global-config-overlay, then re-run global-config."); - $LogPrint info $0 ($NotificationMessage); - - :if ([ :len $GlobalConfigChanges ] > 0) do={ - :set NotificationMessage ($NotificationMessage . "\n\nChanges:"); - :for I from=($ExpectedConfigVersionBefore + 1) to=$ExpectedConfigVersion do={ - :local Change ($GlobalConfigChanges->[ :tostr $I ]); - :set NotificationMessage ($NotificationMessage . "\n " . \ - [ $SymbolForNotification "pushpin" "*" ] . $Change); - $LogPrint info $0 ("Change " . $I . ": " . $Change); - } - } else={ - :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); - } - - :if ($NoNewsAndChangesNotification != true) do={ - :local Link; - :if ($IDonate != true) do={ - :set NotificationMessage ($NotificationMessage . \ - "\n\n==== donation hint ====\n" . \ - "This project is developed in private spare time and usage is " . \ - "free of charge for you. If you like the scripts and think this is " . \ - "of value for you or your business please consider a donation."); - :set Link "https://rsc.eworm.de/#donate"; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "pushpin" ] . "News and configuration changes"); \ - message=$NotificationMessage; link=$Link }); - } - - :set GlobalConfigChanges; - :set GlobalConfigMigration; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# lock script against multiple invocation -:set ScriptLock do={ - :local Script [ :tostr $1 ]; - :local WaitMax ([ :tonum $3 ] * 10); - - :global GetRandom20CharAlNum; - :global IfThenElse; - :global LogPrint; - - :global ScriptLockOrder; - :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ - :set ScriptLockOrder ({}); - } - :if ([ :typeof ($ScriptLockOrder->$Script) ] = "nothing") do={ - :set ($ScriptLockOrder->$Script) ({}); - } - - :local JobCount do={ - :local Script [ :tostr $1 ]; - - :return [ :len [ /system/script/job/find where script=$Script ] ]; - } - - :local TicketCount do={ - :local Script [ :tostr $1 ]; - - :global ScriptLockOrder; - - :local Count 0; - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ([ :typeof $Ticket ] != "nothing") do={ - :set Count ($Count + 1); - } - } - :return $Count; - } - - :local IsFirstTicket do={ - :local Script [ :tostr $1 ]; - :local Check [ :tostr $2 ]; - - :global ScriptLockOrder; - - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ($Ticket = $Check) do={ :return true; } - :if ([ :typeof $Ticket ] != "nothing" && $Ticket != $Check) do={ :return false; } - } - :return false; - } - - :local AddTicket do={ - :local Script [ :tostr $1 ]; - :local Add [ :tostr $2 ]; - - :global ScriptLockOrder; - - :while (true) do={ - :local Pos [ :len ($ScriptLockOrder->$Script) ]; - :set ($ScriptLockOrder->$Script->$Pos) $Add; - :delay 10ms; - :if (($ScriptLockOrder->$Script->$Pos) = $Add) do={ :return true; } - } - } - - :local RemoveTicket do={ - :local Script [ :tostr $1 ]; - :local Remove [ :tostr $2 ]; - - :global ScriptLockOrder; - - :foreach Id,Ticket in=($ScriptLockOrder->$Script) do={ - :while (($ScriptLockOrder->$Script->$Id) = $Remove) do={ - :set ($ScriptLockOrder->$Script->$Id); - :delay 10ms; - } - } - } - - :local CleanupTickets do={ - :local Script [ :tostr $1 ]; - - :global ScriptLockOrder; - - :foreach Ticket in=($ScriptLockOrder->$Script) do={ - :if ([ :typeof $Ticket ] != "nothing") do={ - :return false; - } - } - - :set ($ScriptLockOrder->$Script) ({}); - } - - :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrint error $0 ("A script named '" . $Script . "' does not exist!"); - :error false; - } - - :if ([ $JobCount $Script ] = 0) do={ - $LogPrint error $0 ("No script '" . $Script . "' is running!"); - :error false; - } - - :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ - $LogPrint error $0 ("More tickets than running scripts '" . $Script . "', resetting!"); - :set ($ScriptLockOrder->$Script) ({}); - /system/script/job/remove [ find where script=$Script ]; - } - - :local MyTicket [ $GetRandom20CharAlNum 6 ]; - $AddTicket $Script $MyTicket; - - :local WaitCount 0; - :while ($WaitMax > $WaitCount && \ - ([ $IsFirstTicket $Script $MyTicket ] = false || \ - [ $TicketCount $Script ] < [ $JobCount $Script ])) do={ - :set WaitCount ($WaitCount + 1); - :delay 100ms; - } - - :if ([ $IsFirstTicket $Script $MyTicket ] = true && \ - [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ - $RemoveTicket $Script $MyTicket; - $CleanupTickets $Script; - :return true; - } - - $RemoveTicket $Script $MyTicket; - $LogPrint debug $0 ("Script '" . $Script . "' started more than once" . \ - [ $IfThenElse ($WaitCount > 0) " and timed out waiting for lock" "" ] . "..."); - :return false; -} - -# send notification via NotificationFunctions - expects at least two string arguments -:set SendNotification do={ :do { - :global SendNotification2; - - $SendNotification2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via NotificationFunctions - expects one array argument -:set SendNotification2 do={ - :local Notification $1; - - :global NotificationFunctions; - - :foreach FunctionName,Discard in=$NotificationFunctions do={ - ($NotificationFunctions->$FunctionName) \ - ("\$NotificationFunctions->\"" . $FunctionName . "\"") \ - $Notification; - } -} - -# return UTF-8 symbol for unicode name -:set SymbolByUnicodeName do={ - :local Name [ :tostr $1 ]; - - :global LogPrintOnce; - - :local Symbols { - "abacus"="\F0\9F\A7\AE"; - "alarm-clock"="\E2\8F\B0"; - "arrow-down"="\E2\AC\87"; - "arrow-up"="\E2\AC\86"; - "calendar"="\F0\9F\93\85"; - "card-file-box"="\F0\9F\97\83"; - "chart-decreasing"="\F0\9F\93\89"; - "chart-increasing"="\F0\9F\93\88"; - "cloud"="\E2\98\81"; - "cross-mark"="\E2\9D\8C"; - "earth"="\F0\9F\8C\8D"; - "fire"="\F0\9F\94\A5"; - "floppy-disk"="\F0\9F\92\BE"; - "gear"="\E2\9A\99"; - "heart"="\E2\99\A5"; - "high-voltage-sign"="\E2\9A\A1"; - "incoming-envelope"="\F0\9F\93\A8"; - "information"="\E2\84\B9"; - "large-orange-circle"="\F0\9F\9F\A0"; - "large-red-circle"="\F0\9F\94\B4"; - "link"="\F0\9F\94\97"; - "lock-with-ink-pen"="\F0\9F\94\8F"; - "memo"="\F0\9F\93\9D"; - "mobile-phone"="\F0\9F\93\B1"; - "pushpin"="\F0\9F\93\8C"; - "scissors"="\E2\9C\82"; - "smiley-partying-face"="\F0\9F\A5\B3"; - "smiley-smiling-face"="\E2\98\BA"; - "smiley-winking-face-with-tongue"="\F0\9F\98\9C"; - "sparkles"="\E2\9C\A8"; - "speech-balloon"="\F0\9F\92\AC"; - "star"="\E2\AD\90"; - "warning-sign"="\E2\9A\A0"; - "white-heavy-check-mark"="\E2\9C\85" - } - - :if ([ :len ($Symbols->$Name) ] = 0) do={ - $LogPrintOnce warning $0 ("No symbol available for name '" . $Name . "'!"); - :return ""; - } - - :return (($Symbols->$Name) . "\EF\B8\8F"); -} - -# return symbol for notification -:set SymbolForNotification do={ - :global NotificationsWithSymbols; - :global SymbolByUnicodeName; - :global IfThenElse; - - :if ($NotificationsWithSymbols != true) do={ - :return [ $IfThenElse ([ :len $2 ] > 0) ([ :tostr $2 ] . " ") "" ]; - } - :local Return ""; - :foreach Symbol in=[ :toarray $1 ] do={ - :set Return ($Return . [ $SymbolByUnicodeName $Symbol ]); - } - :return ($Return . " "); -} - -# convert line endings, UNIX -> DOS -:set Unix2Dos do={ - :return [ :tocrlf [ :tostr $1 ] ]; -} - -# url encoding -:set UrlEncode do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars ("\n\r !\"#\$%&'()*+,:;<=>?@[\\]^`{|}~"); - :local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27"; - "%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F"; - "%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$Replace); - } - :set Return ($Return . $Char); - } - - :return $Return; -} - -# basic syntax validation -:set ValidateSyntax do={ - :local Code [ :tostr $1 ]; - - :do { - [ :parse (":local Validate do={\n" . $Code . "\n}") ]; - } on-error={ - :return false; - } - :return true; -} - -# convert version string to numeric value -:set VersionToNum do={ - :local Input [ :tostr $1 ]; - :local Multi 0x1000000; - :local Return 0; - - :global CharacterReplace; - - :set Input [ $CharacterReplace $Input "." "," ]; - :foreach I in={ "zero"; "alpha"; "beta"; "rc" } do={ - :set Input [ $CharacterReplace $Input $I ("," . $I . ",") ]; - } - - :foreach Value in=([ :toarray $Input ], 0) do={ - :local Num [ :tonum $Value ]; - :if ($Multi = 0x100) do={ - :if ([ :typeof $Num ] = "num") do={ - :set Return ($Return + 0xff00); - :set Multi ($Multi / 0x100); - } else={ - :if ($Value = "zero") do={ } - :if ($Value = "alpha") do={ :set Return ($Return + 0x3f00); } - :if ($Value = "beta") do={ :set Return ($Return + 0x5f00); } - :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } - } - } - :if ([ :typeof $Num ] = "num") do={ :set Return ($Return + ($Value * $Multi)); } - :set Multi ($Multi / 0x100); - } - - :return $Return; -} - -# wait for default route to be reachable -:set WaitDefaultRouteReachable do={ - :global IsDefaultRouteReachable; - - :while ([ $IsDefaultRouteReachable ] = false) do={ - :delay 1s; - } -} - -# wait for DNS to resolve -:set WaitDNSResolving do={ - :global IsDNSResolving; - - :while ([ $IsDNSResolving ] = false) do={ - :delay 1s; - } -} - -# wait for file to be available -:set WaitForFile do={ - :local FileName [ :tostr $1 ]; - :local WaitTime [ :totime $2 ]; - - :global CleanFilePath; - :global EitherOr; - :global MAX; - - :set FileName [ $CleanFilePath $FileName ]; - :local I 1; - :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10); - - :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I >= 10) do={ - :return false; - } - :delay $Delay; - :set I ($I + 1); - } - - :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) -:set WaitFullyConnected do={ - :global WaitDefaultRouteReachable; - :global WaitDNSResolving; - :global WaitTimeSync; - - $WaitDefaultRouteReachable; - $WaitTimeSync; - $WaitDNSResolving; -} - -# wait for time to become synced -:set WaitTimeSync do={ - :global IsTimeSync; - - :while ([ $IsTimeSync ] = false) do={ - :delay 1s; - } -} - -# load modules -:foreach Script in=[ /system/script/find where name ~ "^mod/." ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :if ([ $ValidateSyntax ($ScriptVal->"source") ] = true) do={ - :do { - /system/script/run $Script; - } on-error={ - $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run."); - } - } else={ - $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); - } -} - -# Log success -:local Resource [ /system/resource/get ]; -$LogPrintOnce info $ScriptName ("Loaded on " . $Resource->"board-name" . \ - " with RouterOS " . $Resource->"version" . "."); - -# signal we are ready -:set GlobalFunctionsReady true; diff --git a/global-wait b/global-wait new file mode 100644 index 0000000..edb156b --- /dev/null +++ b/global-wait @@ -0,0 +1,13 @@ +#!rsc by RouterOS +# RouterOS script: global-wait +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# wait for global-functions to finish +# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md + +:global GlobalFunctionsReady; + +:while ($GlobalFunctionsReady != true) do={ + :delay 500ms; +} diff --git a/global-wait.rsc b/global-wait.rsc deleted file mode 100644 index ca3fc0c..0000000 --- a/global-wait.rsc +++ /dev/null @@ -1,12 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: global-wait -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# wait for global-functions to finish -# https://rsc.eworm.de/doc/global-wait.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/gps-track b/gps-track new file mode 100644 index 0000000..1f7d228 --- /dev/null +++ b/gps-track @@ -0,0 +1,31 @@ +#!rsc by RouterOS +# RouterOS script: gps-track +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# track gps data by sending json data to http server +# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md + +:global GpsTrackUrl; +:global Identity; + +:global LogPrintExit; + +:local CoordinateFormat [ /system gps get coordinate-format ]; +:local Gps [ / system gps monitor once as-value ]; + +if ($Gps->"valid" = true) do={ + :tool fetch check-certificate=yes-without-crl \ + $GpsTrackUrl output=none \ + http-method=post http-header-field="Content-Type: application/json" \ + http-data=("{" . \ + "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ + "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ + "\"identity\":\"" . $Identity . "\"" . \ + "}"); + $LogPrintExit debug ("Sending GPS data in " . $CoordinateFormat . " format: " . \ + "lat: " . ($Gps->"latitude") . " " . \ + "lon: " . ($Gps->"longitude")) false; +} else={ + $LogPrintExit debug ("GPS data not valid.") false; +} diff --git a/gps-track.rsc b/gps-track.rsc deleted file mode 100644 index dea56d2..0000000 --- a/gps-track.rsc +++ /dev/null @@ -1,53 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: gps-track -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch -# -# track gps data by sending json data to http server -# https://rsc.eworm.de/doc/gps-track.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global GpsTrackUrl; - :global Identity; - - :global FetchUserAgentStr; - :global LogPrint; - :global ScriptLock; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - $WaitFullyConnected; - - :local CoordinateFormat [ /system/gps/get coordinate-format ]; - :local Gps [ /system/gps/monitor once as-value ]; - - :if ($Gps->"valid" = true) do={ - :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - http-header-field=({ [ $FetchUserAgentStr $ScriptName ]; "Content-Type: application/json" }) \ - http-data=[ :serialize to=json { "identity"=$Identity; \ - "lat"=($Gps->"latitude"); "lon"=($Gps->"longitude") } ] $GpsTrackUrl as-value; - $LogPrint debug $ScriptName ("Sending GPS data in " . $CoordinateFormat . " format: " . \ - "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")); - } on-error={ - $LogPrint warning $ScriptName ("Failed sending GPS data!"); - } - } else={ - $LogPrint debug $ScriptName ("GPS data not valid."); - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa b/hotspot-to-wpa new file mode 100644 index 0000000..ca11775 --- /dev/null +++ b/hotspot-to-wpa @@ -0,0 +1,36 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa +# Copyright (c) 2019-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md + +:global LogPrintExit; + +:local MacAddress $"mac-address"; +:local UserName $username; +:local Date [ / system clock get date ]; +:local PassWord [ / ip hotspot user get [ find where name=$UserName ] password ]; + +:if ([ :len [ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ + / caps-man access-list add comment="--- hotspot-to-wpa above ---" disabled=yes; + $LogPrintExit warning "Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'." false; +} +:local PlaceBefore ([ / caps-man access-list find where comment="--- hotspot-to-wpa above ---" disabled ]->0); + +$LogPrintExit info ("Adding/updating accesslist entry for mac address " . $MacAddress . \ + " (user " . $UserName . ").") false; + +/ caps-man access-list remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; + +:local Limits [ / caps-man access-list get $PlaceBefore ]; +:if (($Limits->"ap-tx-limit") > 0 && ($Limits->"client-tx-limit") > 0) do={ + / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" \ + ap-tx-limit=($Limits->"ap-tx-limit") client-tx-limit=($Limits->"client-tx-limit") \ + place-before=$PlaceBefore; +} else={ + / caps-man access-list add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ + mac-address=$MacAddress private-passphrase=$PassWord ssid-regexp="-wpa\$" place-before=$PlaceBefore; +} diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc deleted file mode 100644 index 033d0e7..0000000 --- a/hotspot-to-wpa-cleanup.capsman.rsc +++ /dev/null @@ -1,80 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup.capsman -# Copyright (c) 2021-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=80 -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# manage and clean up private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :local DHCPServers ({}); - :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; - } - } - - :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static."); - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } - } - } - - :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) mac-address ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list."); - /caps-man/access-list/remove $Client; - } - } - - :foreach Server,Timeout in=$DHCPServers do={ - :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc deleted file mode 100644 index 0f8c490..0000000 --- a/hotspot-to-wpa-cleanup.template.rsc +++ /dev/null @@ -1,87 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup%TEMPL% -# Copyright (c) 2021-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=80 -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# manage and clean up private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :local DHCPServers ({}); - :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; - } - } - - :foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :local ClientVal [ /interface/wifi/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static."); - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } - } - } - - :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \ - :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) mac-address ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :local ClientVal [ /interface/wifi/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list."); - /caps-man/access-list/remove $Client; - /interface/wifi/access-list/remove $Client; - } - } - - :foreach Server,Timeout in=$DHCPServers do={ - :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc deleted file mode 100644 index dfec697..0000000 --- a/hotspot-to-wpa-cleanup.wifi.rsc +++ /dev/null @@ -1,80 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup.wifi -# Copyright (c) 2021-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# provides: lease-script, order=80 -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# manage and clean up private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :local DHCPServers ({}); - :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ - :local ServerVal [ /ip/dhcp-server/get $Server ] - :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ]; - :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={ - :set ($DHCPServers->($ServerVal->"name")) \ - [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ]; - } - } - - :foreach Client in=[ /interface/wifi/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /interface/wifi/registration-table/get $Client ]; - :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ - mac-address=($ClientVal->"mac-address") ] do={ - :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static."); - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } - } - } - - :foreach Client in=[ /interface/wifi/access-list/find where comment~"^hotspot-to-wpa:" \ - !(comment~[ /system/clock/get date ]) mac-address ] do={ - :local ClientVal [ /interface/wifi/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list."); - /interface/wifi/access-list/remove $Client; - } - } - - :foreach Server,Timeout in=$DHCPServers do={ - :local TimeoutExtra ($Timeout + [ /system/clock/get time ]); - :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ - server=$Server last-seen>$TimeoutExtra comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrint info $ScriptName ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for " . ($LeaseVal->"last-seen") . ", removing."); - /interface/wifi/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc deleted file mode 100644 index 3f51475..0000000 --- a/hotspot-to-wpa.capsman.rsc +++ /dev/null @@ -1,105 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa.capsman -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :set ExitOK true; - :error false; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :set ExitOK true; - :error true; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; - } - :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; - :if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; - } - - :delay 2s; - /caps-man/access-list/set $Entry action=accept; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc deleted file mode 100644 index 068241d..0000000 --- a/hotspot-to-wpa.template.rsc +++ /dev/null @@ -1,125 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa%TEMPL% -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! This is just a template to generate the real script! -# !! Pattern '%TEMPL%' is replaced, paths are filtered. - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :set ExitOK true; - :error false; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /caps-man/access-list/find where \ - :if ([ :len [ /interface/wifi/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /caps-man/access-list/get ([ find where \ - :local Template [ /interface/wifi/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :set ExitOK true; - :error true; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /caps-man/access-list/add private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -# NOT /caps-man/ # - :set ($Template->"private-passphrase") ($Template->"passphrase"); -# NOT /caps-man/ # - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - /interface/wifi/access-list/set $Entry !passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - } -# NOT /interface/wifi/ # - :local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; - :if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; - } -# NOT /interface/wifi/ # - - :delay 2s; - /caps-man/access-list/set $Entry action=accept; - /interface/wifi/access-list/set $Entry action=accept; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc deleted file mode 100644 index cc5e2fc..0000000 --- a/hotspot-to-wpa.wifi.rsc +++ /dev/null @@ -1,102 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa.wifi -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, hotspot -# -# add private WPA passphrase after hotspot login -# https://rsc.eworm.de/doc/hotspot-to-wpa.md -# -# !! Do not edit this file, it is generated from template! - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :local MacAddress $"mac-address"; - :local UserName $username; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); - :set ExitOK true; - :error false; - } - - :local Date [ /system/clock/get date ]; - :local UserVal ({}); - :if ([ :len [ /ip/hotspot/user/find where name=$UserName ] ] > 0) do={ - :set UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; - } - :local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; - :local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - - :if ([ :len [ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'."); - } - :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - - :if ([ :len [ /interface/wifi/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /interface/wifi/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrint warning $ScriptName ("Added template in access-list for hotspot '" . $Hotspot . "'."); - } - :local Template [ /interface/wifi/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - - :if ($Template->"action" = "reject") do={ - $LogPrint info $ScriptName ("Ignoring login for hotspot '" . $Hotspot . "'."); - :set ExitOK true; - :error true; - } - - # allow login page to load - :delay 1s; - - $LogPrint info $ScriptName ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ")."); - /interface/wifi/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; - /interface/wifi/access-list/add passphrase=($UserVal->"password") ssid-regexp="-wpa\$" \ - mac-address=$MacAddress comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - action=reject place-before=$PlaceBefore; - - :local Entry [ /interface/wifi/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; - :set ($Template->"private-passphrase") ($Template->"passphrase"); - :local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; - :if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /interface/wifi/access-list/set $Entry !passphrase; - } else={ - /interface/wifi/access-list/set $Entry passphrase=$PrivatePassphrase; - } - } - :local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; - :if ([ :len $SsidRegexp ] > 0) do={ - /interface/wifi/access-list/set $Entry ssid-regexp=$SsidRegexp; - } - :local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; - :if ([ :len $VlanId ] > 0) do={ - /interface/wifi/access-list/set $Entry vlan-id=$VlanId; - } - - :delay 2s; - /interface/wifi/access-list/set $Entry action=accept; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/ip-addr-bridge b/ip-addr-bridge new file mode 100644 index 0000000..762c74e --- /dev/null +++ b/ip-addr-bridge @@ -0,0 +1,18 @@ +#!rsc by RouterOS +# RouterOS script: ip-addr-bridge +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# enable or disable ip addresses based on bridge port state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ip-addr-bridge.md + +:foreach Bridge in=[ / interface bridge find ] do={ + :local BrName [ / interface bridge get $Bridge name ]; + :if ([ :len [ / interface bridge port find where bridge=$BrName ] ] > 0) do={ + :if ([ :len [ / interface bridge port find where bridge=$BrName and inactive=no ] ] = 0) do={ + / ip address disable [ find where !dynamic interface=$BrName ]; + } else={ + / ip address enable [ find where !dynamic interface=$BrName ]; + } + } +} diff --git a/ip-addr-bridge.rsc b/ip-addr-bridge.rsc deleted file mode 100644 index 68ff4a4..0000000 --- a/ip-addr-bridge.rsc +++ /dev/null @@ -1,18 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# enable or disable ip addresses based on bridge port state -# https://rsc.eworm.de/doc/ip-addr-bridge.md - -:foreach Bridge in=[ /interface/bridge/find ] do={ - :local BrName [ /interface/bridge/get $Bridge name ]; - :if ([ :len [ /interface/bridge/port/find where bridge=$BrName ] ] > 0) do={ - :if ([ :len [ /interface/bridge/port/find where bridge=$BrName and inactive=no ] ] = 0) do={ - /ip/address/disable [ find where !dynamic interface=$BrName ]; - } else={ - /ip/address/enable [ find where !dynamic interface=$BrName ]; - } - } -} diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc deleted file mode 100644 index 26dab0a..0000000 --- a/ipsec-to-dns.rsc +++ /dev/null @@ -1,84 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, ipsec -# -# and add/remove/update DNS entries from IPSec mode-config -# https://rsc.eworm.de/doc/ipsec-to-dns.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Domain; - :global HostNameInZone; - :global Identity; - :global PrefixInZone; - - :global CharacterReplace; - :global EscapeForRegEx; - :global IfThenElse; - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); - :local Ttl 5m; - :local CommentPrefix ("managed by " . $ScriptName . " for "); - :local CommentString ("--- " . $ScriptName . " above ---"); - - :if ([ :len [ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add name=$CommentString type=NXDOMAIN disabled=yes; - $LogPrint warning $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'."); - } - :local PlaceBefore ([ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ]->0); - - :foreach DnsRecord in=[ /ip/dns/static/find where comment~("^" . $CommentPrefix) ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/ipsec/active-peers/find where id~("^(CN=)?" . [ $EscapeForRegEx $PeerId ] . "\$") \ - dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ - $LogPrint debug $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry."); - } else={ - :local Found false; - $LogPrint info $ScriptName ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry."); - /ip/dns/static/remove $DnsRecord; - } - } - - :foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local PeerId [ $CharacterReplace ($PeerVal->"id") "CN=" "" ]; - :local Comment ($CommentPrefix . $PeerId); - :local HostName [ :pick $PeerId 0 [ :find ($PeerId . ".") "." ] ]; - - :local Fqdn ($HostName . "." . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :if ($DnsIp = $PeerVal->"dynamic-address") do={ - $LogPrint debug $ScriptName ("DNS entry for " . $Fqdn . " does not need updating."); - } else={ - $LogPrint info $ScriptName ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . "."); - /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; - } - } else={ - $LogPrint info $ScriptName ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . "."); - /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/ipv6-update b/ipv6-update new file mode 100644 index 0000000..d5b15c4 --- /dev/null +++ b/ipv6-update @@ -0,0 +1,56 @@ +#!rsc by RouterOS +# RouterOS script: ipv6-update +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update firewall and dns settings on IPv6 prefix change +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md + +:local PdPrefix $"pd-prefix"; + +:global LogPrintExit; +:global ParseKeyValueStore; + +:if ([ :typeof $PdPrefix ] = "nothing") do={ + $LogPrintExit error "This script is supposed to run from ipv6 dhcp-client." true; +} + +:local Pool [ / ipv6 pool get [ find where prefix=$PdPrefix ] name ]; +:if ([ :len [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ + / ipv6 firewall address-list add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); + :log warning ("Added ipv6 address list entry for ipv6-pool-" . $Pool . "."); +} +:local AddrList [ / ipv6 firewall address-list find where comment=("ipv6-pool-" . $Pool) ]; +:local OldPrefix [ / ipv6 firewall address-list get ($AddrList->0) address ]; + +:if ($OldPrefix != $PdPrefix) do={ + :log info ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); + / ipv6 firewall address-list set address=$PdPrefix $AddrList; + + # give the interfaces a moment to receive their addresses + :delay 2s; + + :foreach ListEntry in=[ / ipv6 firewall address-list find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local ListEntryVal [ / ipv6 firewall address-list get $ListEntry ]; + :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; + + :local Address [ / ipv6 address find where from-pool=$Pool interface=($Comment->"interface") ]; + :if ([ :len $Address ] = 1) do={ + :set Address [ / ipv6 address get $Address address ]; + :log info ("Updating IPv6 address list with new IPv6 prefix " . $Address . " from interface " . ($Comment->"interface")); + / ipv6 firewall address-list set address=$Address $ListEntry; + } + } + + :foreach Record in=[ / ip dns static find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ + :local RecordVal [ / ip dns static get $Record ]; + :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; + + :local Prefix [ / ipv6 address get [ find where interface=($Comment->"interface") from-pool=$Pool global ] address ]; + :set Prefix [ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ]; + :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); + + :log info ("Updating DNS record for " . ($RecordVal->"name") . ($RecordVal->"regexp") . " to " . $Address); + / ip dns static set address=$Address $Record; + } +} diff --git a/ipv6-update.rsc b/ipv6-update.rsc deleted file mode 100644 index 94bd1bc..0000000 --- a/ipv6-update.rsc +++ /dev/null @@ -1,107 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ipv6-update -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update firewall and dns settings on IPv6 prefix change -# https://rsc.eworm.de/doc/ipv6-update.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ParseKeyValueStore; - :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; - :error false; - } - - :if ([ :typeof $NaAddress ] = "str") do={ - $LogPrint info $ScriptName ("An address (" . $NaAddress . ") was acquired, not a prefix. Ignoring."); - :set ExitOK true; - :error false; - } - - :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; - $LogPrint warning $ScriptName ("Added dynamic ipv6 address list entry for ipv6-pool-" . $Pool); - } - :local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; - :local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; - - :if ($OldPrefix != $PdPrefix) do={ - $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix); - /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; - - # give the interfaces a moment to receive their addresses - :delay 2s; - - :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; - :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; - - :if ([ :typeof [ :find ($ListEntryVal->"address") "/128" ] ] = "num" ) do={ - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($ListEntryVal->"address"); - :local Address ($Prefix | ([ :toip6 [ :pick $Address 0 [ :find $Address "/128" ] ] ] & ::ffff:ffff:ffff:ffff)); - - $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 host address " . $Address . \ - " from interface " . ($Comment->"interface")); - /ipv6/firewall/address-list/set address=$Address $ListEntry; - } else={ - $LogPrint info $ScriptName ("Updating IPv6 address list with new IPv6 prefix " . $Prefix . \ - " from interface " . ($Comment->"interface")); - /ipv6/firewall/address-list/set address=$Prefix $ListEntry; - } - } - } - - :foreach Record in=[ /ip/dns/static/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local RecordVal [ /ip/dns/static/get $Record ]; - :local Comment [ $ParseKeyValueStore ($RecordVal->"comment") ]; - - :local Prefix [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") global ]; - :if ([ :len $Prefix ] = 1) do={ - :set Prefix [ /ipv6/address/get $Prefix address ]; - :set Prefix ([ :toip6 [ :pick $Prefix 0 [ :find $Prefix "/64" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - - $LogPrint info $ScriptName ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address); - /ip/dns/static/set address=$Address $Record; - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/learn-mac-based-vlan b/learn-mac-based-vlan new file mode 100644 index 0000000..e301a47 --- /dev/null +++ b/learn-mac-based-vlan @@ -0,0 +1,13 @@ +#!rsc by RouterOS +# RouterOS script: learn-mac-based-vlan +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# learn MAC address for MAC-based-VLAN + +:local NewVlanId 33; + +:if ([ :len [ / interface ethernet switch mac-based-vlan find where src-mac-address=$leaseActMAC ] ] = 0 ) do={ + :log info ("MAC-based-VLAN: learning MAC address " . $leaseActMAC . " for VLAN " . $NewVlanId . "."); + / interface ethernet switch mac-based-vlan add src-mac-address=$leaseActMAC new-customer-vid=$NewVlanId; +} diff --git a/lease-script b/lease-script new file mode 100644 index 0000000..438df0f --- /dev/null +++ b/lease-script @@ -0,0 +1,49 @@ +#!rsc by RouterOS +# RouterOS script: lease-script +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run scripts on DHCP lease +# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md + +:global LogPrintExit; + +:if ([ :typeof $leaseActIP ] = "nothing" || \ + [ :typeof $leaseActMAC ] = "nothing" || \ + [ :typeof $leaseServerName ] = "nothing" || \ + [ :typeof $leaseBound ] = "nothing") do={ + $LogPrintExit error "This script is supposed to run from ip dhcp-server." true; +} + +:local Scripts; +:local ScriptsAssign { + "dhcp-to-dns"; + "collect-wireless-mac.local"; + "dhcp-lease-comment.local"; + "collect-wireless-mac.capsman"; + "dhcp-lease-comment.capsman" +} +:local ScriptsDeAssign { + "dhcp-to-dns" +} + +:local State ""; +:if ($leaseBound = 0) do={ + :set State "de"; + :set Scripts $ScriptsDeAssign; +} else={ + :set Scripts $ScriptsAssign; +} + +:log debug ("DHCP Server " . $leaseServerName . " " . \ + $State . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); + +# delay a moment to update the lease table, do not run in parallel for de/assign +:delay ((1 + $leaseBound) . "s"); + +:foreach Script in=$Scripts do={ + :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ + :log debug ("Running script from lease-script: " . $Script); + / system script run $Script; + } +} diff --git a/lease-script.rsc b/lease-script.rsc deleted file mode 100644 index bf27fda..0000000 --- a/lease-script.rsc +++ /dev/null @@ -1,65 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: lease-script -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# run scripts on DHCP lease -# https://rsc.eworm.de/doc/lease-script.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Grep; - :global IfThenElse; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ :typeof $leaseActIP ] = "nothing" || \ - [ :typeof $leaseActMAC ] = "nothing" || \ - [ :typeof $leaseServerName ] = "nothing" || \ - [ :typeof $leaseBound ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from ip dhcp-server."); - :set ExitOK true; - :error false; - } - - $LogPrint debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); - - :if ([ $ScriptLock $ScriptName 10 ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ - $LogPrint debug $ScriptName ("More invocations are waiting, exiting early."); - :set ExitOK true; - :error true; - } - - :local RunOrder ({}); - :foreach Script in=[ /system/script/find where source~("\n# provides: lease-script\\b") ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: lease-script, ") ] ]; - - :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); - } - - :foreach Order,Script in=$RunOrder do={ - :do { - $LogPrint debug $ScriptName ("Running script with order " . $Order . ": " . $Script); - /system/script/run $Script; - } on-error={ - $LogPrint warning $ScriptName ("Running script '" . $Script . "' failed!"); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/leds-day-mode b/leds-day-mode new file mode 100644 index 0000000..4d77469 --- /dev/null +++ b/leds-day-mode @@ -0,0 +1,9 @@ +#!rsc by RouterOS +# RouterOS script: leds-day-mode +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# enable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +/ system leds settings set all-leds-off=never; diff --git a/leds-day-mode.rsc b/leds-day-mode.rsc deleted file mode 100644 index 7344fde..0000000 --- a/leds-day-mode.rsc +++ /dev/null @@ -1,9 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: leds-day-mode -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# enable LEDs -# https://rsc.eworm.de/doc/leds-mode.md - -/system/leds/settings/set all-leds-off=never; diff --git a/leds-night-mode b/leds-night-mode new file mode 100644 index 0000000..89ac834 --- /dev/null +++ b/leds-night-mode @@ -0,0 +1,9 @@ +#!rsc by RouterOS +# RouterOS script: leds-night-mode +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# disable LEDs +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +/ system leds settings set all-leds-off=immediate; diff --git a/leds-night-mode.rsc b/leds-night-mode.rsc deleted file mode 100644 index 8bd028e..0000000 --- a/leds-night-mode.rsc +++ /dev/null @@ -1,9 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: leds-night-mode -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# disable LEDs -# https://rsc.eworm.de/doc/leds-mode.md - -/system/leds/settings/set all-leds-off=immediate; diff --git a/leds-toggle-mode b/leds-toggle-mode new file mode 100644 index 0000000..6ee81c8 --- /dev/null +++ b/leds-toggle-mode @@ -0,0 +1,13 @@ +#!rsc by RouterOS +# RouterOS script: leds-toggle-mode +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# toggle LEDs mode +# https://git.eworm.de/cgit/routeros-scripts/about/doc/leds-mode.md + +:if ([ / system leds settings get all-leds-off ] = "never") do={ + / system leds settings set all-leds-off=immediate; +} else={ + / system leds settings set all-leds-off=never; +} diff --git a/leds-toggle-mode.rsc b/leds-toggle-mode.rsc deleted file mode 100644 index b55e351..0000000 --- a/leds-toggle-mode.rsc +++ /dev/null @@ -1,9 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# toggle LEDs mode -# https://rsc.eworm.de/doc/leds-mode.md - -/system/leds/settings/set all-leds-off=(({ "never"="immediate"; "immediate"="never" })->[ get all-leds-off ]); diff --git a/log-forward b/log-forward new file mode 100644 index 0000000..feebedd --- /dev/null +++ b/log-forward @@ -0,0 +1,69 @@ +#!rsc by RouterOS +# RouterOS script: log-forward +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# forward log messages via notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md + +:global Identity; +:global LogForwardFilter; +:global LogForwardFilterMessage; +:global LogForwardLast; +:global LogForwardRateLimit; + +:global IfThenElse; +:global LogPrintExit; +:global MailServerIsUp; +:global ScriptLock; +:global SendNotification; +:global SymbolForNotification; +:global WaitFullyConnected; + +$ScriptLock "log-forward"; + +:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ + :set LogForwardRateLimit 0; +} + +:if ($LogForwardRateLimit > 30) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + $LogPrintExit info ("Rate limit in action, not forwarding logs, if any!") true; +} + +$WaitFullyConnected; + +:if ([ $MailServerIsUp ] = false) do={ + $LogPrintExit warning ("Mail server is not up.") true; +} + +:local Count 0; +:local Messages ""; +:local MessageVal; + +:foreach Message in=[ / log find where !(topics~$LogForwardFilter) !(message~$LogForwardFilterMessage) ] do={ + :set MessageVal [ / log get $Message ]; + + :if ($LogForwardLast = ($MessageVal->".id")) do={ + :set Messages ""; + :set Count 0; + } else={ + :set Messages ($Messages . "\n" . $MessageVal->"time" . " " . \ + [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); + :set Count ($Count + 1); + } +} + +:if ($Count > 0) do={ + $SendNotification ([ $SymbolForNotification "warning-sign" ] . "Log Forwarding") \ + ("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) \ + "this message" ("these " . $Count . " messages") ] . " after " . \ + [ / system resource get uptime ] . " uptime.\n" . $Messages); + + :set LogForwardRateLimit ($LogForwardRateLimit + 10); + :set LogForwardLast ($MessageVal->".id"); +} else={ + :if ($LogForwardRateLimit > 0) do={ + :set LogForwardRateLimit ($LogForwardRateLimit - 1); + } +} diff --git a/log-forward.rsc b/log-forward.rsc deleted file mode 100644 index afeb3f2..0000000 --- a/log-forward.rsc +++ /dev/null @@ -1,113 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: log-forward -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# forward log messages via notification -# https://rsc.eworm.de/doc/log-forward.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - :global LogForwardFilter; - :global LogForwardFilterMessage; - :global LogForwardInclude; - :global LogForwardIncludeMessage; - :global LogForwardLast; - :global LogForwardRateLimit; - - :global EitherOr; - :global HexToNum; - :global IfThenElse; - :global LogForwardFilterLogForwarding; - :global LogPrint; - :global MAX; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ - :set LogForwardRateLimit 0; - } - - :if ($LogForwardRateLimit > 30) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrint info $ScriptName ("Rate limit in action, not forwarding logs, if any!"); - :set ExitOK true; - :error false; - } - - :local Count 0; - :local Duplicates false; - :local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; - :local Messages ""; - :local Warning false; - :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 \ - !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ - topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ - :set MessageVal [ /log/get $Message ]; - :local Bullet "information"; - - :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ - :local DupCount ($MessageDups->($MessageVal->"message")); - :if ($MessageVal->"topics" ~ "(warning)") do={ - :set Warning true; - :set Bullet "large-orange-circle"; - } - :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error)") do={ - :set Warning true; - :set Bullet "large-red-circle"; - } - :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . [ $SymbolForNotification $Bullet ] . \ - $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); - } else={ - :set Duplicates true; - } - :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); - :set Count ($Count + 1); - } - } - - :if ($Count > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit + 10); - - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ - "Log Forwarding"); \ - message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ - ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ - [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ - [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ - "\n" . $Messages) }); - } else={ - :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; - } - - :local LogAll [ /log/find ]; - :set LogForwardLast ($LogAll->([ :len $LogAll ] - 1) ); -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/logo.avif b/logo.avif deleted file mode 100644 index 399a2f5..0000000 Binary files a/logo.avif and /dev/null differ diff --git a/logo.png b/logo.png deleted file mode 100644 index d97b75d..0000000 Binary files a/logo.png and /dev/null differ diff --git a/logo.svg b/logo.svg deleted file mode 100644 index a30e04e..0000000 --- a/logo.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/manage-umts b/manage-umts new file mode 100644 index 0000000..b8426bd --- /dev/null +++ b/manage-umts @@ -0,0 +1,29 @@ +#!rsc by RouterOS +# RouterOS script: manage-umts +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# manage UMTS interface based on ethernet and wireless status + +:local EtherInt "en1"; +:local WlanInt "wl-station"; +:local UmtsInt "t-mobile"; + +:local EtherStatus [ / interface ethernet get $EtherInt running ]; +:local WlanStatus [ / interface wireless get $WlanInt running ]; + +:if ($EtherStatus = true || $WlanStatus = true) do={ + :if ([ / interface get $UmtsInt disabled ] = false) do={ + :log info ("Ethernet (" . $EtherInt . " / " . $EtherStatus . ") or " . \ + "wireless (" . $WlanInt . " / " . $WlanStatus . ") is running, " . \ + "UMTS interface " . $UmtsInt . " is enabled. Disabling..."); + / interface set disabled=yes $UmtsInt; + } +} else={ + :if ([ / interface get $UmtsInt disabled ] = true) do={ + :log info ("Neither ethernet (" . $EtherInt . ") nor wireless (" . \ + $WlanInt . ") interface is running, UMTS interface " . $UmtsInt . \ + " is disabled. Enabling..."); + / interface set disabled=no $UmtsInt; + } +} diff --git a/mod/bridge-port-to.rsc b/mod/bridge-port-to.rsc deleted file mode 100644 index 39a036e..0000000 --- a/mod/bridge-port-to.rsc +++ /dev/null @@ -1,70 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# reset bridge ports to default bridge -# https://rsc.eworm.de/doc/mod/bridge-port-to.md - -:global BridgePortTo; - -:set BridgePortTo do={ :do { - :local BridgePortTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrint; - :global ParseKeyValueStore; - - :local InterfaceReEnable ({}); - :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ - :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :foreach Config,BridgeDefault in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $BridgePortTo) do={ - :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($BridgeDefault = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); - :return false; - } - :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrint info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); - /interface/bridge/port/disable $BridgePort; - :delay 200ms; - /ip/dhcp-client/enable $DHCPClient; - } - } else={ - :if ($BridgePortVal->"disabled" = true || $BridgeDefault != $BridgePortVal->"bridge") do={ - $LogPrint info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client."); - :if ([ :len $DHCPClient ] = 1) do={ - /ip/dhcp-client/disable $DHCPClient; - :delay 200ms; - } - :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; - :if ([ :len $Disable ] > 0) do={ - /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $Disable); - } - /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; - } else={ - $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . "."); - } - } - } - } - } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 5s; - $LogPrint info $0 ("Re-enabling interfaces..."); - /interface/ethernet/enable $InterfaceReEnable; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } diff --git a/mod/bridge-port-vlan.rsc b/mod/bridge-port-vlan.rsc deleted file mode 100644 index 0eeb9b5..0000000 --- a/mod/bridge-port-vlan.rsc +++ /dev/null @@ -1,79 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# manage VLANs on bridge ports -# https://rsc.eworm.de/doc/mod/bridge-port-vlan.md - -:global BridgePortVlan; - -:global BridgePortVlan do={ :do { - :local ConfigTo [ :tostr $1 ]; - - :global IfThenElse; - :global LogPrint; - :global ParseKeyValueStore; - - :local InterfaceReEnable ({}); - :foreach BridgePort in=[ /interface/bridge/port/find where !(comment=[]) ] do={ - :local BridgePortVal [ /interface/bridge/port/get $BridgePort ]; - :foreach Config,Vlan in=[ $ParseKeyValueStore ($BridgePortVal->"comment") ] do={ - :if ($Config = $ConfigTo) do={ - :local DHCPClient [ /ip/dhcp-client/find where interface=$BridgePortVal->"interface" comment="toggle with bridge port" ]; - - :if ($Vlan = "dhcp-client") do={ - :if ([ :len $DHCPClient ] != 1) do={ - $LogPrint warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!"); - :return false; - } - :local DHCPClientDisabled [ /ip/dhcp-client/get $DHCPClient disabled ]; - - :if ($BridgePortVal->"disabled" = false || $DHCPClientDisabled = true) do={ - $LogPrint info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client."); - /interface/bridge/port/disable $BridgePort; - :delay 200ms; - /ip/dhcp-client/enable $DHCPClient; - } - } else={ - :local VlanName $Vlan; - :if ($Vlan != [ :tostr [ :tonum $Vlan ] ]) do={ - :do { - :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); - } on-error={ - $LogPrint warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!"); - :return false; - } - } - :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ - $LogPrint info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client."); - :if ([ :len $DHCPClient ] = 1) do={ - /ip/dhcp-client/disable $DHCPClient; - :delay 200ms; - } - :local Disable [ /interface/ethernet/find where name=$BridgePortVal->"interface" ]; - :if ([ :len $Disable ] > 0) do={ - /interface/ethernet/disable $Disable; - :set InterfaceReEnable ($InterfaceReEnable, $Disable); - } - /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; - } else={ - $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ - " vlan " . $Vlan . "."); - } - } - } - } - } - :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 5s; - $LogPrint info $0 ("Re-enabling interfaces..."); - /interface/ethernet/enable $InterfaceReEnable; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } diff --git a/mod/inspectvar.rsc b/mod/inspectvar.rsc deleted file mode 100644 index c861557..0000000 --- a/mod/inspectvar.rsc +++ /dev/null @@ -1,60 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/inspectvar -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# inspect variables -# https://rsc.eworm.de/doc/mod/inspectvar.md - -:global InspectVar; -:global InspectVarReturn; - -# inspect variable and print on terminal -:set InspectVar do={ :do { - :global InspectVarReturn; - - :put [ :tocrlf [ $InspectVarReturn $1 ] ]; -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# inspect variable and return formatted string -:set InspectVarReturn do={ - :local Input $1; - :local Level (0 + [ :tonum $2 ]); - - :global IfThenElse; - :global InspectVarReturn; - - :local IndentReturn do={ - :local Prefix [ :tostr $1 ]; - :local Value [ :tostr $2 ]; - :local Level [ :tonum $3 ]; - - :local Indent ""; - :for I from=1 to=$Level step=1 do={ - :set Indent ($Indent . " "); - } - :return ($Indent . "-" . $Prefix . "-> " . $Value); - } - - :local TypeOf [ :typeof $Input ]; - :local Return [ $IndentReturn "type" $TypeOf $Level ]; - - :if ($TypeOf = "array") do={ - :foreach Key,Value in=$Input do={ - :set $Return ($Return . "\n" . \ - [ $IndentReturn "key" $Key ($Level + 1) ] . "\n" . \ - [ $InspectVarReturn $Value ($Level + 2) ]); - } - } else={ - :if ($TypeOf != "nothing") do={ - :set $Return ($Return . "\n" . \ - [ $IndentReturn "value" [ $IfThenElse ([ :len $Input ] > 80) \ - ([ :pick $Input 0 77 ] . "...") $Input ] $Level ]); - } - } - :return $Return; -} diff --git a/mod/ipcalc.rsc b/mod/ipcalc.rsc deleted file mode 100644 index 477cf4a..0000000 --- a/mod/ipcalc.rsc +++ /dev/null @@ -1,53 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/ipcalc -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# ip address calculation -# https://rsc.eworm.de/doc/mod/ipcalc.md - -:global IPCalc; -:global IPCalcReturn; - -# print netmask, network, min host, max host and broadcast -:set IPCalc do={ :do { - :local Input [ :tostr $1 ]; - - :global FormatLine; - :global IPCalcReturn; - - :local Values [ $IPCalcReturn $1 ]; - - :put [ :tocrlf ( \ - [ $FormatLine "Address" ($Values->"address") ] . "\n" . \ - [ $FormatLine "Netmask" ($Values->"netmask") ] . "\n" . \ - [ $FormatLine "Network" ($Values->"network") ] . "\n" . \ - [ $FormatLine "HostMin" ($Values->"hostmin") ] . "\n" . \ - [ $FormatLine "HostMax" ($Values->"hostmax") ] . "\n" . \ - [ $FormatLine "Broadcast" ($Values->"broadcast") ]) ]; -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# calculate and return netmask, network, min host, max host and broadcast -:set IPCalcReturn do={ - :local Input [ :tostr $1 ]; - :local Address [ :toip [ :pick $Input 0 [ :find $Input "/" ] ] ]; - :local Bits [ :tonum [ :pick $Input ([ :find $Input "/" ] + 1) [ :len $Input ] ] ]; - :local Mask ((255.255.255.255 << (32 - $Bits)) & 255.255.255.255); - - :local Return { - "address"=$Address; - "netmask"=$Mask; - "networkaddress"=($Address & $Mask); - "networkbits"=$Bits; - "network"=(($Address & $Mask) . "/" . $Bits); - "hostmin"=(($Address & $Mask) | 0.0.0.1); - "hostmax"=(($Address | ~$Mask) ^ 0.0.0.1); - "broadcast"=($Address | ~$Mask); - } - - :return $Return; -} diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc deleted file mode 100644 index 7b89d98..0000000 --- a/mod/notification-email.rsc +++ /dev/null @@ -1,266 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/notification-email -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, email, scheduler -# -# send notifications via e-mail -# https://rsc.eworm.de/doc/mod/notification-email.md - -:global EMailGenerateFrom; -:global FlushEmailQueue; -:global LogForwardFilterLogForwarding; -:global NotificationEMailSubject; -:global NotificationFunctions; -:global PurgeEMailQueue; -:global QuotedPrintable; -:global SendEMail; -:global SendEMail2; - -# generate from-property with display name -:set EMailGenerateFrom do={ - :global Identity; - - :global CleanName; - - :local From [ /tool/e-mail/get from ]; - - :if ($From ~ "<.*>\$") do={ - :return $From; - } - - :return ([ $CleanName $Identity ] . " via routeros-scripts <" . $From . ">"); -} - -# flush e-mail queue -:set FlushEmailQueue do={ :do { - :global EmailQueue; - - :global EitherOr; - :global EMailGenerateFrom; - :global IsDNSResolving; - :global IsTimeSync; - :global LogPrint; - - :local AllDone true; - :local QueueLen [ :len $EmailQueue ]; - :local Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; - - :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ - $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); - /system/scheduler/remove $Scheduler; - :return false; - } - - :if ($QueueLen = 0) do={ - :return true; - } - - :if ([ :len $Scheduler ] < 0) do={ - /system/scheduler/add name="_FlushEmailQueue" interval=1m start-time=startup \ - comment="Doing initial checks..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); - :set Scheduler [ /system/scheduler/find where name="_FlushEmailQueue" ]; - } - - :local SchedVal [ /system/scheduler/get $Scheduler ]; - :if (($SchedVal->"interval") < 1m) do={ - /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; - } - - :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrint debug $0 ("Sending mail is currently in progress, not flushing."); - :return false; - } - - :if ([ $IsTimeSync ] = false) do={ - $LogPrint debug $0 ("Time is not synced, not flushing."); - :return false; - } - - :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :typeof [ :toip ($EMailSettings->"server") ] ] != "ip" && [ $IsDNSResolving ] = false) do={ - $LogPrint debug $0 ("Server address is a DNS name and resolving fails, not flushing."); - :return false; - } - - /system/scheduler/set interval=($QueueLen . "m") comment="Sending..." $Scheduler; - - :foreach Id,Message in=$EmailQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :local Attach ({}); - :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } - :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ - :if ([ :len [ /file/find where name=$File ] ] = 1) do={ - :set Attach ($Attach, $File); - } else={ - $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={ - :set AllDone false; - :set Wait false; - } - } while=($Wait = true); - } - } - - :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={ - /system/scheduler/remove $Scheduler; - :set EmailQueue; - :return true; - } - - :if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0 && \ - [ :typeof $EmailQueue ] = "nothing") do={ - $LogPrint info $0 ("Queue was purged? Exiting."); - :return false; - } - - /system/scheduler/set interval=(($SchedVal->"run-count") . "m") \ - comment="Waiting for retry..." $Scheduler; -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# generate filter for log-forward -:set LogForwardFilterLogForwarding do={ - :global EscapeForRegEx; - :global NotificationEMailSubject; - :global SymbolForNotification; - - :return ("^Error sending e-mail <(" . \ - [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ - "memo" ] . "Log Forwarding") ] ] . "|" . \ - [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ - "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); -} - -# generate the e-mail subject -:set NotificationEMailSubject do={ - :global Identity; - :global IdentityExtra; - - :global QuotedPrintable; - - :return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ]; -} - -# send notification via e-mail - expects one array argument -:set ($NotificationFunctions->"email") do={ - :local Notification $1; - - :global EmailGeneralTo; - :global EmailGeneralToOverride; - :global EmailGeneralCc; - :global EmailGeneralCcOverride; - :global EmailQueue; - - :global EitherOr; - :global IfThenElse; - :global NotificationEMailSignature; - :global NotificationEMailSubject; - - :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; - :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - - :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || ($EMailSettings->"server") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ - :return false; - } - - :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue ({}); - } - :local Signature [ $EitherOr [ $NotificationEMailSignature ] [ /system/note/get note ] ]; - :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$To; cc=$Cc; - subject=[ $NotificationEMailSubject ($Notification->"subject") ]; - body=(($Notification->"message") . \ - [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \ - [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \ - attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") }; - :if ([ :len [ /system/scheduler/find where name="_FlushEmailQueue" ] ] = 0) do={ - /system/scheduler/add name="_FlushEmailQueue" interval=1s start-time=startup \ - comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); - } -} - -# purge the e-mail queue -:set PurgeEMailQueue do={ - :global EmailQueue; - - /system/scheduler/remove [ find where name="_FlushEmailQueue" ]; - :set EmailQueue; -} - -# convert string to quoted-printable -:global QuotedPrintable do={ - :local Input [ :tostr $1 ]; - - :global CharacterMultiply; - - :if ([ :len $Input ] = 0) do={ - :return $Input; - } - - :local Return ""; - :local Chars ( \ - "\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F" . \ - [ $CharacterMultiply ("\00") 29 ] . "=\00?" . [ $CharacterMultiply ("\00") 63 ] . "\7F" . \ - "\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97\98\99\9A\9B\9C\9D\9E\9F" . \ - "\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF" . \ - "\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF" . \ - "\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); - :local Hex "0123456789ABCDEF"; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ("=" . [ :pick $Hex ($Replace / 16)] . [ :pick $Hex ($Replace % 16) ]); - } - :set Return ($Return . $Char); - } - - :if ($Input = $Return) do={ - :return $Input; - } - - :return ("=?utf-8?Q?" . $Return . "?="); -} - -# send notification via e-mail - expects at least two string arguments -:set SendEMail do={ :do { - :global SendEMail2; - - $SendEMail2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via e-mail - expects one array argument -:set SendEMail2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; -} diff --git a/mod/notification-matrix.rsc b/mod/notification-matrix.rsc deleted file mode 100644 index e989ee0..0000000 --- a/mod/notification-matrix.rsc +++ /dev/null @@ -1,271 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2025 Michael Gisbers -# Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch, scheduler -# -# send notifications via Matrix -# https://rsc.eworm.de/doc/mod/notification-matrix.md - -:global FlushMatrixQueue; -:global NotificationFunctions; -:global PurgeMatrixQueue; -:global SendMatrix; -:global SendMatrix2; -:global SetupMatrixAuthenticate; -:global SetupMatrixJoinRoom; - -# flush Matrix queue -:set FlushMatrixQueue do={ :do { - :global MatrixQueue; - - :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 $MatrixQueue ]; - - :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrint warning $0 ("Flushing Matrix messages from scheduler, but queue is empty."); - } - - :foreach Id,Message in=$MatrixQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - /tool/fetch check-certificate=yes-without-crl output=none \ - http-header-field=($Message->"headers") http-method=post \ - http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=($Message->"plain"); - "format"="org.matrix.custom.html"; "formatted_body"=($Message->"formatted") } ] \ - ("https://" . $Message->"homeserver" . "/_matrix/client/r0/rooms/" . $Message->"room" . \ - "/send/m.room.message?access_token=" . $Message->"accesstoken") as-value; - :set ($MatrixQueue->$Id); - } on-error={ - $LogPrint debug $0 ("Sending queued Matrix message failed."); - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; - :set MatrixQueue; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via Matrix - expects one array argument -:set ($NotificationFunctions->"matrix") do={ - :local Notification $1; - - :global Identity; - :global IdentityExtra; - :global MatrixAccessToken; - :global MatrixAccessTokenOverride; - :global MatrixHomeServer; - :global MatrixHomeServerOverride; - :global MatrixQueue; - :global MatrixRoom; - :global MatrixRoomOverride; - - :global EitherOr; - :global FetchUserAgentStr; - :global LogPrint; - :global ProtocolStrip; - :global SymbolForNotification; - - :local PrepareText do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return ""; - } - - :local Return ""; - :local Chars { "\""; "\n"; "&"; "<"; ">" }; - :local Subs { """; "
"; "&"; "<"; ">" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ([ :typeof $Replace ] = "num") do={ - :set Char ($Subs->$Replace); - } - :set Return ($Return . $Char); - } - - :return $Return; - } - - :local AccessToken [ $EitherOr ($MatrixAccessTokenOverride->($Notification->"origin")) $MatrixAccessToken ]; - :local HomeServer [ $EitherOr ($MatrixHomeServerOverride->($Notification->"origin")) $MatrixHomeServer ]; - :local Room [ $EitherOr ($MatrixRoomOverride->($Notification->"origin")) $MatrixRoom ]; - - :if ([ :len $AccessToken ] = 0 || [ :len $HomeServer ] = 0 || [ :len $Room ] = 0) do={ - :return false; - } - - :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ] }); - :local Plain ("## [" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```"); - :local Formatted ("

" . [ $PrepareText ("[" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject")) ] . "

" . "
" . \
-    [ $PrepareText ($Notification->"message") ] . "
"); - :if ([ :len ($Notification->"link") ] > 0) do={ - :local Label [ $ProtocolStrip ($Notification->"link") ]; - :set Plain ($Plain . "\n" . [ $SymbolForNotification "link" ] . \ - "[" . $Label . "](" . $Notification->"link" . ")"); - :set Formatted ($Formatted . "
" . [ $SymbolForNotification "link" ] . \ - ""link") ] . "\">" . \ - [ $PrepareText $Label ] . ""); - } - - :do { - /tool/fetch check-certificate=yes-without-crl output=none \ - http-header-field=$Headers http-method=post \ - http-data=[ :serialize to=json { "msgtype"="m.text"; "body"=$Plain; - "format"="org.matrix.custom.html"; "formatted_body"=$Formatted } ] \ - ("https://" . $HomeServer . "/_matrix/client/r0/rooms/" . $Room . \ - "/send/m.room.message?access_token=" . $AccessToken) as-value; - } on-error={ - $LogPrint info $0 ("Failed sending Matrix notification! Queuing..."); - - :if ([ :typeof $MatrixQueue ] = "nothing") do={ - :set MatrixQueue ({}); - } - :local Symbol [ $SymbolForNotification "alarm-clock" ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :set Plain ($Plain . "\n" . $Symbol . "This message was queued since *" . \ - $DateTime . "* and may be obsolete."); - :set Formatted ($Formatted . "
" . $Symbol . "This message was queued since " . \ - $DateTime . " and may be obsolete."); - :set ($MatrixQueue->[ :len $MatrixQueue ]) { headers=$Headers; \ - accesstoken=$AccessToken; homeserver=$HomeServer; room=$Room; \ - plain=$Plain; formatted=$Formatted }; - :if ([ :len [ /system/scheduler/find where name="_FlushMatrixQueue" ] ] = 0) do={ - /system/scheduler/add name="_FlushMatrixQueue" interval=1m start-time=startup \ - on-event=(":global FlushMatrixQueue; \$FlushMatrixQueue;"); - } - } -} - -# purge the Matrix queue -:set PurgeMatrixQueue do={ - :global MatrixQueue; - - /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; - :set MatrixQueue; -} - -# send notification via Matrix - expects at least two string arguments -:set SendMatrix do={ :do { - :global SendMatrix2; - - $SendMatrix2 ({ origin=$0; subject=$1; message=$2; link=$3 }); -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via Matrix - expects one array argument -:set SendMatrix2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; -} - -# setup - get home server and access token -:set SetupMatrixAuthenticate do={ - :local User [ :tostr $1 ]; - :local Pass [ :tostr $2 ]; - - :global FetchUserAgentStr; - :global LogPrint; - - :global MatrixAccessToken; - :global MatrixHomeServer; - - :local Domain [ :pick $User ([ :find $User ":" ] + 1) [ :len $User] ]; - :do { - :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ - ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); - :set MatrixHomeServer ([ :deserialize from=json value=$Data ]->"m.homeserver"->"base_url"); - $LogPrint debug $0 ("Home server is: " . $MatrixHomeServer); - } on-error={ - $LogPrint error $0 ("Failed getting home server!"); - :return false; - } - - :if ([ :pick $MatrixHomeServer 0 8 ] = "https://") do={ - :set MatrixHomeServer [ :pick $MatrixHomeServer 8 [ :len $MatrixHomeServer ] ]; - } - - :do { - :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post \ - http-data=[ :serialize to=json { "type"="m.login.password"; "user"=$User; "password"=$Pass } ] \ - ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); - :set MatrixAccessToken ([ :deserialize from=json value=$Data ]->"access_token"); - $LogPrint debug $0 ("Access token is: " . $MatrixAccessToken); - } on-error={ - $LogPrint error $0 ("Failed logging in (and getting access token)!"); - :return false; - } - - :do { - /system/script/remove [ find where name="global-config-overlay.d/mod/notification-matrix" ]; - /system/script/add name="global-config-overlay.d/mod/notification-matrix" source=( \ - "# configuration snippet: mod/notification-matrix\n\n" . \ - ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ - ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); - $LogPrint info $0 ("Added configuration snippet. Now create and join a room, please!"); - } on-error={ - $LogPrint error $0 ("Failed adding configuration snippet!"); - :return false; - } -} - -# setup - join a room -:set SetupMatrixJoinRoom do={ - :global MatrixRoom [ :tostr $1 ]; - - :global FetchUserAgentStr; - :global LogPrint; - :global UrlEncode; - - :global MatrixAccessToken; - :global MatrixHomeServer; - :global MatrixRoom; - - :do { - /tool/fetch check-certificate=yes-without-crl output=none \ - http-header-field=({ [ $FetchUserAgentStr $0 ] }) http-method=post http-data="" \ - ("https://" . $MatrixHomeServer . "/_matrix/client/r0/rooms/" . [ $UrlEncode $MatrixRoom ] . \ - "/join?access_token=" . [ $UrlEncode $MatrixAccessToken ]) as-value; - $LogPrint debug $0 ("Joined the room."); - } on-error={ - $LogPrint error $0 ("Failed joining the room!"); - :return false; - } - - :do { - :local Snippet [ /system/script/find where name="global-config-overlay.d/mod/notification-matrix" ]; - /system/script/set $Snippet source=([ get $Snippet source ] . \ - ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); - $LogPrint info $0 ("Appended configuration to configuration snippet. Please review!"); - } on-error={ - $LogPrint error $0 ("Failed appending configuration to snippet!"); - :return false; - } -} diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc deleted file mode 100644 index aac6d6c..0000000 --- a/mod/notification-ntfy.rsc +++ /dev/null @@ -1,162 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/notification-ntfy -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch, scheduler -# -# send notifications via Ntfy (ntfy.sh) -# https://rsc.eworm.de/doc/mod/notification-ntfy.md - -:global FlushNtfyQueue; -:global NotificationFunctions; -:global PurgeNtfyQueue; -:global SendNtfy; -:global SendNtfy2; - -# flush ntfy queue -:set FlushNtfyQueue do={ :do { - :global NtfyQueue; - :global NtfyMessageIDs; - - :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 $NtfyQueue ]; - - :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrint warning $0 ("Flushing Ntfy messages from scheduler, but queue is empty."); - } - - :foreach Id,Message in=$NtfyQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :do { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - http-header-field=($Message->"headers") http-data=($Message->"text") \ - ($Message->"url") as-value; - :set ($NtfyQueue->$Id); - } on-error={ - $LogPrint debug $0 ("Sending queued Ntfy message failed."); - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $NtfyQueue ]) do={ - /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; - :set NtfyQueue; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via ntfy - expects one array argument -:set ($NotificationFunctions->"ntfy") do={ - :local Notification $1; - - :global Identity; - :global IdentityExtra; - :global NtfyQueue; - :global NtfyServer; - :global NtfyServerOverride; - :global NtfyServerPass; - :global NtfyServerPassOverride; - :global NtfyServerToken; - :global NtfyServerTokenOverride; - :global NtfyServerUser; - :global NtfyServerUserOverride; - :global NtfyTopic; - :global NtfyTopicOverride; - - :global CertificateAvailable; - :global EitherOr; - :global FetchUserAgentStr; - :global IfThenElse; - :global LogPrint; - :global SymbolForNotification; - :global UrlEncode; - - :local Server [ $EitherOr ($NtfyServerOverride->($Notification->"origin")) $NtfyServer ]; - :local User [ $EitherOr ($NtfyServerUserOverride->($Notification->"origin")) $NtfyServerUser ]; - :local Pass [ $EitherOr ($NtfyServerPassOverride->($Notification->"origin")) $NtfyServerPass ]; - :local Token [ $EitherOr ($NtfyServerTokenOverride->($Notification->"origin")) $NtfyServerToken ]; - :local Topic [ $EitherOr ($NtfyTopicOverride->($Notification->"origin")) $NtfyTopic ]; - - :if ([ :len $Topic ] = 0) do={ - :return false; - } - - :local Url ("https://" . $Server . "/" . [ $UrlEncode $Topic ]); - :local Headers ({ [ $FetchUserAgentStr ($Notification->"origin") ]; \ - ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ - ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); - :if ([ :len $User ] > 0 || [ :len $Pass ] > 0) do={ - :set Headers ($Headers, ("Authorization: Basic " . [ :convert to=base64 ($User . ":" . $Pass) ])); - } - :if ([ :len $Token ] > 0) do={ - :set Headers ($Headers, ("Authorization: Bearer " . $Token)); - } - :local Text (($Notification->"message") . "\n"); - :if ([ :len ($Notification->"link") ] > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")); - } - - :do { - :if ($Server = "ntfy.sh") do={ - :if ([ $CertificateAvailable "ISRG Root X1" ] = false) do={ - $LogPrint warning $0 ("Downloading required certificate failed."); - :error false; - } - } - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ - http-header-field=$Headers http-data=$Text $Url as-value; - } on-error={ - $LogPrint info $0 ("Failed sending ntfy notification! Queuing..."); - - :if ([ :typeof $NtfyQueue ] = "nothing") do={ - :set NtfyQueue ({}); - } - :set Text ($Text . "\n" . [ $SymbolForNotification "alarm-clock" ] . \ - "This message was queued since " . [ /system/clock/get date ] . " " . \ - [ /system/clock/get time ] . " and may be obsolete."); - :set ($NtfyQueue->[ :len $NtfyQueue ]) \ - { url=$Url; headers=$Headers; text=$Text }; - :if ([ :len [ /system/scheduler/find where name="_FlushNtfyQueue" ] ] = 0) do={ - /system/scheduler/add name="_FlushNtfyQueue" interval=1m start-time=startup \ - on-event=(":global FlushNtfyQueue; \$FlushNtfyQueue;"); - } - } -} - -# purge the Ntfy queue -:set PurgeNtfyQueue do={ - :global NtfyQueue; - - /system/scheduler/remove [ find where name="_FlushNtfyQueue" ]; - :set NtfyQueue; -} - -# send notification via ntfy - expects at least two string arguments -:set SendNtfy do={ :do { - :global SendNtfy2; - - $SendNtfy2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via ntfy - expects one array argument -:set SendNtfy2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"ntfy") ("\$NotificationFunctions->\"ntfy\"") $Notification; -} diff --git a/mod/notification-telegram.rsc b/mod/notification-telegram.rsc deleted file mode 100644 index 68e913f..0000000 --- a/mod/notification-telegram.rsc +++ /dev/null @@ -1,243 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch, scheduler -# -# send notifications via Telegram -# https://rsc.eworm.de/doc/mod/notification-telegram.md - -:global FlushTelegramQueue; -:global GetTelegramChatId; -:global NotificationFunctions; -:global PurgeTelegramQueue; -:global SendTelegram; -:global SendTelegram2; - -# flush telegram queue -:set FlushTelegramQueue do={ :do { - :global TelegramQueue; - :global TelegramMessageIDs; - - :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 $TelegramQueue ]; - - :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] > 0 && $QueueLen = 0) do={ - $LogPrint warning $0 ("Flushing Telegram messages from scheduler, but queue is empty."); - } - - :foreach Id,Message in=$TelegramQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :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=($Message->"http-data") as-value ]->"data"); - :set ($TelegramQueue->$Id); - :set ($TelegramMessageIDs->[ :tostr ([ :deserialize from=json value=$Data ]->"result"->"message_id") ]) 1; - } on-error={ - $LogPrint debug $0 ("Sending queued Telegram message failed."); - :set AllDone false; - } - } - } - - :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; - :set TelegramQueue; - } -} on-error={ - :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; - - :global Identity; - :global IdentityExtra; - :global TelegramChatId; - :global TelegramChatIdOverride; - :global TelegramMessageIDs; - :global TelegramQueue; - :global TelegramThreadId; - :global TelegramThreadIdOverride; - :global TelegramTokenId; - :global TelegramTokenIdOverride; - - :global CertificateAvailable; - :global CharacterReplace; - :global EitherOr; - :global IfThenElse; - :global LogPrint; - :global ProtocolStrip; - :global SymbolForNotification; - :global UrlEncode; - - :local EscapeMD do={ - :local Text [ :tostr $1 ]; - :local Mode [ :tostr $2 ]; - :local Excl [ :tostr $3 ]; - - :global CharacterReplace; - :global IfThenElse; - - :local Chars { - "body"={ "\\"; "`" }; - "plain"={ "_"; "*"; "["; "]"; "("; ")"; "~"; "`"; ">"; - "#"; "+"; "-"; "="; "|"; "{"; "}"; "."; "!" }; - } - :foreach Char in=($Chars->$Mode) do={ - :if ([ :typeof [ :find $Excl $Char ] ] = "nil") do={ - :set Text [ $CharacterReplace $Text $Char ("\\" . $Char) ]; - } - } - - :if ($Mode = "body") do={ - :return ("```\n" . $Text . "\n```"); - } - - :return $Text; - } - - :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={ - :return false; - } - - :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={ - :set TelegramMessageIDs ({}); - } - - :local Truncated false; - :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ - ($Notification->"subject")) "plain" ] . "__*\n\n"); - :local LenSubject [ :len $Text ]; - :local LenMessage [ :len ($Notification->"message") ]; - :local LenLink ([ :len ($Notification->"link") ] * 2); - :local LenSum ($LenSubject + $LenMessage + $LenLink); - :if ($LenSum > 3968) do={ - :set Text ($Text . [ $EscapeMD ([ :pick ($Notification->"message") 0 (3840 - $LenSubject - $LenLink) ] . "...") "body" ]); - :set Truncated true; - } else={ - :set Text ($Text . [ $EscapeMD ($Notification->"message") "body" ]); - } - :if ($LenLink > 0) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . \ - "[" . [ $EscapeMD [ $ProtocolStrip ($Notification->"link") ] "plain" ] . "]" . \ - "(" . [ $EscapeMD ($Notification->"link") "plain" ] . ")"); - } - :if ($Truncated = true) do={ - :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The message was too long and has been truncated, cut off _" . \ - (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%_!") "plain" "_" ]); - } - - :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."); - :error false; - } - :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ - ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ - http-data=($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..."); - - :if ([ :typeof $TelegramQueue ] = "nothing") do={ - :set TelegramQueue ({}); - } - :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 ]) { 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;"); - } - } -} - -# purge the Telegram queue -:set PurgeTelegramQueue do={ - :global TelegramQueue; - - /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; - :set TelegramQueue; -} - -# send notification via telegram - expects at least two string arguments -:set SendTelegram do={ :do { - :global SendTelegram2; - - $SendTelegram2 ({ origin=$0; subject=$1; message=$2; link=$3; silent=$4 }); -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# send notification via telegram - expects one array argument -:set SendTelegram2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"telegram") ("\$NotificationFunctions->\"telegram\"") $Notification; -} diff --git a/mod/scriptrunonce.rsc b/mod/scriptrunonce.rsc deleted file mode 100644 index 7fcd5b5..0000000 --- a/mod/scriptrunonce.rsc +++ /dev/null @@ -1,56 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# download script and run it once -# https://rsc.eworm.de/doc/mod/scriptrunonce.md - -:global ScriptRunOnce; - -# fetch and run script(s) once -:set ScriptRunOnce do={ :do { - :local Scripts [ :toarray $1 ]; - - :global ScriptRunOnceBaseUrl; - :global ScriptRunOnceUrlSuffix; - - :global FetchHuge; - :global LogPrint; - :global ValidateSyntax; - - :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https?|sftp)://")) do={ - :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrint warning $0 ("Script '" . $Script . "' is not an url and base url is not available."); - :return false; - } - :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); - } - - :local Source [ $FetchHuge $0 $Script true ]; - :if ($Source = false) do={ - $LogPrint warning $0 ("Failed fetching script '" . $Script . "'!"); - :return false; - } - - :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; -} } diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc deleted file mode 100644 index 2fae4b1..0000000 --- a/mod/ssh-keys-import.rsc +++ /dev/null @@ -1,114 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/ssh-keys-import -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.16 -# -# import ssh keys for public key authentication -# https://rsc.eworm.de/doc/mod/ssh-keys-import.md - -:global SSHKeysImport; -:global SSHKeysImportFile; - -# import single key passed as string -:set SSHKeysImport do={ :do { - :local Key [ :tostr $1 ]; - :local User [ :tostr $2 ]; - - :global GetRandom20CharAlNum; - :global LogPrint; - :global MkDir; - :global RmDir; - :global WaitForFile; - - :if ([ :len $Key ] = 0 || [ :len $User ] = 0) do={ - $LogPrint warning $0 ("Missing argument(s), please pass key and user!"); - :return false; - } - - :if ([ :len [ /user/find where name=$User ] ] = 0) do={ - $LogPrint warning $0 ("User '" . $User . "' does not exist."); - :return false; - } - - :local KeyVal ([ :deserialize $Key delimiter=" " from=dsv options=dsv.plain ]->0); - :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ - $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); - :return false; - } - - :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex ($KeyVal->1) ]; - - :if ([ :len [ /user/ssh-keys/find where user=$User key-owner~("\\bmd5=" . $FingerPrintMD5 . "\\b") ] ] > 0) do={ - $LogPrint warning $0 ("The ssh public key (MD5:" . $FingerPrintMD5 . \ - ") is already available for user '" . $User . "'."); - :return false; - } - - :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ - $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); - :return false; - } - - :local FileName ("tmpfs/ssh-keys-import/key-" . [ $GetRandom20CharAlNum 6 ] . ".pub"); - /file/add name=$FileName contents=($Key . ", md5=" . $FingerPrintMD5); - $WaitForFile $FileName; - - :do { - /user/ssh-keys/import public-key-file=$FileName user=$User; - $LogPrint info $0 ("Imported ssh public key (" . $KeyVal->2 . ", " . $KeyVal->0 . ", " . \ - "MD5:" . $FingerPrintMD5 . ") for user '" . $User . "'."); - $RmDir "tmpfs/ssh-keys-import"; - } on-error={ - $LogPrint warning $0 ("Failed importing key."); - $RmDir "tmpfs/ssh-keys-import"; - :return false; - } -} on-error={ - :global ExitError; $ExitError false $0; -} } - -# import keys from a file -:set SSHKeysImportFile do={ :do { - :local FileName [ :tostr $1 ]; - :local User [ :tostr $2 ]; - - :global EitherOr; - :global LogPrint; - :global ParseKeyValueStore; - :global SSHKeysImport; - - :if ([ :len $FileName ] = 0 || [ :len $User ] = 0) do={ - $LogPrint warning $0 ("Missing argument(s), please pass file name and user!"); - :return false; - } - - :local File [ /file/find where name=$FileName ]; - :if ([ :len $File ] = 0) do={ - $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); - :return false; - } - :local Keys [ :tolf [ /file/get $FileName contents ] ]; - - :foreach KeyVal in=[ :deserialize $Keys delimiter=" " from=dsv options=dsv.plain ] do={ - :local Continue false; - :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ - :do { - $SSHKeysImport ($KeyVal->0 . " " . $KeyVal->1 . " " . $KeyVal->2) $User; - } on-error={ - $LogPrint warning $0 ("Failed importing key for user '" . $User . "'."); - } - :set Continue true; - } - :if ($Continue = false && $KeyVal->0 = "#") do={ - :set User [ $EitherOr ([ $ParseKeyValueStore ($KeyVal->1) ]->"user") $User ]; - :set Continue true; - } - :if ($Continue = false && [ :len ($KeyVal->0) ] > 0) do={ - $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); - } - } -} on-error={ - :global ExitError; $ExitError false $0; -} } diff --git a/mode-button b/mode-button new file mode 100644 index 0000000..35c0899 --- /dev/null +++ b/mode-button @@ -0,0 +1,67 @@ +#!rsc by RouterOS +# RouterOS script: mode-button +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# act on multiple mode and reset button presses +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md + +:global ModeButton; + +:global LogPrintExit; + +:set ($ModeButton->"count") ($ModeButton->"count" + 1); + +:local Scheduler [ / system scheduler find where name="ModeButtonScheduler" ]; + +:if ([ :len $Scheduler ] = 0) do={ + $LogPrintExit info ("Creating scheduler ModeButtonScheduler, counting presses...") false; + :global ModeButtonScheduler do={ + :global ModeButton; + + :global LogPrintExit; + :global ModeButtonScheduler; + + :local LEDInvert do={ + :global ModeButtonLED; + + :global IfThenElse; + + :local LED [ / system leds find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :if ([ :len $LED ] = 0) do={ + :return false; + } + / system leds set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + } + + :local Count ($ModeButton->"count"); + :local Code ($ModeButton->[ :tostr $Count ]); + + :set ($ModeButton->"count") 0; + :set ModeButtonScheduler; + / system scheduler remove ModeButtonScheduler; + + :if ([ :len $Code ] > 0) do={ + $LogPrintExit info ("Acting on " . $Count . " mode-button presses: " . $Code) false; + + :for I from=1 to=$Count do={ + $LEDInvert; + :if ([ / system routerboard settings get silent-boot ] = false) do={ + :beep length=200ms; + } + :delay 200ms; + $LEDInvert; + :delay 200ms; + } + + [ :parse $Code ]; + } else={ + $LogPrintExit info ("No action defined for " . $Count . " mode-button presses.") false; + } + } + / system scheduler add name="ModeButtonScheduler" \ + on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; +} else={ + $LogPrintExit debug ("Updating scheduler ModeButtonScheduler...") false; + / system scheduler set $Scheduler start-time=[ /system clock get time ]; +} diff --git a/mode-button-event b/mode-button-event new file mode 100644 index 0000000..b31ddc3 --- /dev/null +++ b/mode-button-event @@ -0,0 +1,6 @@ +#!rsc by RouterOS +# RouterOS script: mode-button-event + +:global LogPrintExit; + +$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/mode-button-scheduler b/mode-button-scheduler new file mode 100644 index 0000000..8844e49 --- /dev/null +++ b/mode-button-scheduler @@ -0,0 +1,6 @@ +#!rsc by RouterOS +# RouterOS script: mode-button-scheduler + +:global LogPrintExit; + +$LogPrintExit warning ("This script's functionality has been merged into 'mode-button'.") true; diff --git a/mode-button.rsc b/mode-button.rsc deleted file mode 100644 index edc5f40..0000000 --- a/mode-button.rsc +++ /dev/null @@ -1,96 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mode-button -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, scheduler -# -# act on multiple mode and reset button presses -# https://rsc.eworm.de/doc/mode-button.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global ModeButton; - - :global LogPrint; - - :set ($ModeButton->"count") ($ModeButton->"count" + 1); - - :local Scheduler [ /system/scheduler/find where name="_ModeButtonScheduler" ]; - - :if ([ :len $Scheduler ] = 0) do={ - $LogPrint info $ScriptName ("Creating scheduler _ModeButtonScheduler, counting presses..."); - :global ModeButtonScheduler do={ :do { - :local FuncName $0; - - :global ModeButton; - - :global LogPrint; - :global ModeButtonScheduler; - :global ValidateSyntax; - - :local LEDInvert do={ - :global ModeButtonLED; - - :global IfThenElse; - - :local LED [ /system/leds/find where leds=$ModeButtonLED \ - !disabled type~"^(on|off)\$" interface=[] ]; - :if ([ :len $LED ] = 0) do={ - :return false; - } - /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; - } - - :local Count ($ModeButton->"count"); - :local Code ($ModeButton->[ :tostr $Count ]); - - :set ($ModeButton->"count") 0; - :set ModeButtonScheduler; - /system/scheduler/remove [ find where name="_ModeButtonScheduler" ]; - - :if ([ :len $Code ] > 0) do={ - :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrint info $FuncName ("Acting on " . $Count . " mode-button presses: " . $Code); - - :for I from=1 to=$Count do={ - $LEDInvert; - :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ - :beep length=200ms; - } - :delay 200ms; - $LEDInvert; - :delay 200ms; - } - - :do { - [ :parse $Code ]; - } on-error={ - $LogPrint warning $FuncName \ - ("The code for " . $Count . " mode-button presses failed with runtime error!"); - } - } else={ - $LogPrint warning $FuncName \ - ("The code for " . $Count . " mode-button presses failed syntax validation!"); - } - } else={ - $LogPrint info $FuncName ("No action defined for " . $Count . " mode-button presses."); - } - } on-error={ - :global ExitError; $ExitError false $0; - } } - /system/scheduler/add name="_ModeButtonScheduler" \ - on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; - } else={ - $LogPrint debug $ScriptName ("Updating scheduler _ModeButtonScheduler..."); - /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc deleted file mode 100644 index 467d636..0000000 --- a/netwatch-dns.rsc +++ /dev/null @@ -1,150 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: netwatch-dns -# Copyright (c) 2022-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.16 -# requires device-mode, fetch -# -# monitor and manage dns/doh with netwatch -# https://rsc.eworm.de/doc/netwatch-dns.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CertificateAvailable; - :global EitherOr; - :global IsDNSResolving; - :global IsTimeSync; - :global LogPrint; - :global LogPrintOnce; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local SettleTime (5m30s - [ /system/resource/get uptime ]); - :if ($SettleTime > 0s) do={ - $LogPrint info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle."); - :set ExitOK true; - :error true; - } - - :local DnsServers ({}); - :local DnsFallback ({}); - :local DnsCurrent [ /ip/dns/get servers ]; - - :foreach Host in=[ /tool/netwatch/find where comment~"\\bdns\\b" status="up" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - - :if ($HostInfo->"disabled" != true) do={ - :if ($HostInfo->"dns" = true) do={ - :set DnsServers ($DnsServers, $HostVal->"host"); - } - :if ($HostInfo->"dns-fallback" = true) do={ - :set DnsFallback ($DnsFallback, $HostVal->"host"); - } - } - } - - :if ([ :len $DnsServers ] > 0) do={ - :if ($DnsServers != $DnsCurrent) do={ - $LogPrint info $ScriptName ("Updating DNS servers: " . [ :tostr $DnsServers ]); - /ip/dns/set servers=$DnsServers; - /ip/dns/cache/flush; - } - } else={ - :if ([ :len $DnsFallback ] > 0) do={ - :if ($DnsFallback != $DnsCurrent) do={ - $LogPrint info $ScriptName ("Updating DNS servers to fallback: " . [ :tostr $DnsFallback ]); - /ip/dns/set servers=$DnsFallback; - /ip/dns/cache/flush; - } - } - } - - :local DohCurrent [ /ip/dns/get use-doh-server ]; - :local DohServers ({}); - - :if ([ :len $DohCurrent ] > 0 && [ $IsDNSResolving ] = false && [ $IsTimeSync ] = false) do={ - $LogPrint info $ScriptName ("Time is not sync, disabling DoH: " . $DohCurrent); - /ip/dns/set use-doh-server=""; - :set DohCurrent ""; - } - - :foreach Host in=[ /tool/netwatch/find where comment~"\\bdoh\\b" status="up" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostName [ /ip/dns/static/find where name address=($HostVal->"host") \ - (type="A" or type="AAAA") !disabled !dynamic ]; - :if ([ :len $HostName ] > 0) do={ - :set HostName [ /ip/dns/static/get ($HostName->0) name ]; - } - - :if ($HostInfo->"doh" = true && $HostInfo->"disabled" != true) do={ - :if ([ :len ($HostInfo->"doh-url") ] = 0) do={ - :set ($HostInfo->"doh-url") ("https://" . [ $EitherOr $HostName ($HostVal->"host") ] . "/dns-query"); - } - - :if ($DohCurrent = $HostInfo->"doh-url") do={ - $LogPrint debug $ScriptName ("Current DoH server is still up: " . $DohCurrent); - :set ExitOK true; - :error true; - } - - :set ($DohServers->[ :len $DohServers ]) $HostInfo; - } - } - - :if ([ :len $DohCurrent ] > 0) do={ - $LogPrint info $ScriptName ("Current DoH server is down, disabling: " . $DohCurrent); - /ip/dns/set use-doh-server=""; - /ip/dns/cache/flush; - } - - :foreach DohServer in=$DohServers do={ - :if ([ :len ($DohServer->"doh-cert") ] > 0) do={ - :if ([ $CertificateAvailable ($DohServer->"doh-cert") ] = false) do={ - $LogPrint warning $ScriptName ("Downloading certificate failed, trying without."); - } - } - - :local Data false; - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - http-header-field=({ "accept: application/dns-message" }) \ - url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \ - "\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \ - "\00\10" . "\00\01") ]) as-value ]->"data"); - } on-error={ - $LogPrint warning $ScriptName ("Request to DoH server failed (network or certificate issue): " . \ - ($DohServer->"doh-url")); - } - - :if ($Data != false) do={ - :if ([ :typeof [ :find $Data "doh-check-OK" ] ] = "num") do={ - /ip/dns/set use-doh-server=($DohServer->"doh-url") verify-doh-cert=yes; - :if ([ /certificate/settings/get crl-use ] = true) do={ - $LogPrintOnce warning $ScriptName ("Configured to use CRL, that can cause severe issue!"); - } - /ip/dns/cache/flush; - $LogPrint info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")); - :set ExitOK true; - :error true; - } else={ - $LogPrint warning $ScriptName ("Received unexpected response from DoH server: " . \ - ($DohServer->"doh-url")); - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/netwatch-notify b/netwatch-notify new file mode 100644 index 0000000..9651841 --- /dev/null +++ b/netwatch-notify @@ -0,0 +1,84 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-notify +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# monitor netwatch and send notifications +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md + +:global NetwatchNotify; + +:global IfThenElse; +:global LogPrintExit; +:global ParseKeyValueStore; +:global SendNotification; +:global SymbolForNotification; + +:if ([ :typeof $NetwatchNotify ] = "nothing") do={ + :set NetwatchNotify [ :toarray "" ]; +} + +:foreach Host in=[ / tool netwatch find where comment~"^notify," disabled=no ] do={ + :local HostVal [ / tool netwatch get $Host ]; + :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; + :local HostName ($HostInfo->"hostname"); + + :local Metric { "count"=0; "notified"=false }; + :if ([ :typeof ($NetwatchNotify->$HostName) ] = "array") do={ + :set $Metric ($NetwatchNotify->$HostName); + } + + :if ($HostVal->"status" = "up") do={ + $LogPrintExit debug ("Host " . $HostName . " (" . $HostVal->"host" . ") is up.") false; + :local Count ($Metric->"count"); + :set ($Metric->"count") 0; + :if ($Metric->"notified" = true) do={ + $SendNotification ([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $HostName . " up") \ + ("Host " . $HostName . " (" . $HostVal->"host" . ") is up since " . $HostVal->"since" . ".\n" . \ + "It was down for " . $Count . " checks since " . ($Metric->"since") . "."); + :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ + $LogPrintExit info ("Running hook on host " . $HostName . " up: " . ($HostInfo->"up-hook")) false; + [ :parse ($HostInfo->"up-hook") ]; + } + } + :set ($Metric->"notified") false; + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since"); + } else={ + :set ($Metric->"count") ($Metric->"count" + 1); + :set ($Metric->"parent") ($HostInfo->"parent"); + :set ($Metric->"since") ($HostVal->"since"); + :local Count [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; + :local Parent ($HostInfo->"parent"); + :while ([ :len $Parent ] > 0) do={ + :set Count ($Count + 1); + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + :set Parent ($HostInfo->"parent"); + :local ParentNotified false; + :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ + :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) true false ]; + :if ($ParentNotified = false) do={ + :set Parent ($NetwatchNotify->$Parent->"parent"); + } + } + $LogPrintExit info ("Host " . $HostName . " (" . $HostVal->"host" . ") is down for " . \ + $Metric->"count" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ + ($Metric->"notified" = true) ("already notified.") ($Count - $Metric->"count" . " to go.") ] \ + ("parent host " . $Parent . " is down.") ]) false; + :if ($ParentNotified = false && $Metric->"count" >= $Count && $Metric->"notified" != true) do={ + $SendNotification ([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $HostName . " down") \ + ("Host " . $HostName . " (" . $HostVal->"host" . ") is down since " . $HostVal->"since" . "."); + :set ($Metric->"notified") true; + :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ + $LogPrintExit info ("Running hook on host " . $HostName . " down: " . ($HostInfo->"down-hook")) false; + [ :parse ($HostInfo->"down-hook") ]; + } + } + } + :set ($NetwatchNotify->$HostName) { + "count"=($Metric->"count"); + "notified"=($Metric->"notified"); + "parent"=($Metric->"parent"); + "since"=($Metric->"since") }; +} diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc deleted file mode 100644 index 0b8a8dc..0000000 --- a/netwatch-notify.rsc +++ /dev/null @@ -1,229 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: netwatch-notify -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# monitor netwatch and send notifications -# https://rsc.eworm.de/doc/netwatch-notify.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global NetwatchNotify; - - :global EitherOr; - :global IfThenElse; - :global IsDNSResolving; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptFromTerminal; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - - :local NetwatchNotifyHook do={ - :local ScriptName [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Type [ :tostr $3 ]; - :local State [ :tostr $4 ]; - :local Hook [ :tostr $5 ]; - - :global LogPrint; - :global ValidateSyntax; - - :if ([ $ValidateSyntax $Hook ] = true) do={ - :do { - [ :parse $Hook ]; - } on-error={ - $LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed to run."); - :return ("The hook failed to run."); - } - } else={ - $LogPrint warning $ScriptName ("The " . $State . "-hook for " . $Type . " '" . $Name . "' failed syntax validation."); - :return ("The hook failed syntax validation."); - } - - $LogPrint info $ScriptName ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . $Hook); - :return ("Ran hook:\n" . $Hook); - } - - :local ResolveExpected do={ - :local ScriptName [ :tostr $1 ]; - :local Name [ :tostr $2 ]; - :local Expected [ :tostr $3 ]; - - :global GetRandom20CharAlNum; - - :local FwAddrList ($ScriptName . "-" . [ $GetRandom20CharAlNum ]); - :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; - } - } - :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; - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :local ScriptFromTerminalCached [ $ScriptFromTerminal $ScriptName ]; - - :if ([ :typeof $NetwatchNotify ] = "nothing") do={ - :set NetwatchNotify ({}); - } - - :foreach Host in=[ /tool/netwatch/find where comment~"\\bnotify\\b" !disabled status!="unknown" ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local Type [ $IfThenElse ($HostVal->"type" ~ "^(https?-get|tcp-conn)\$") "service" "host" ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - :local HostDetails ($HostVal->"host" . \ - [ $IfThenElse ([ :len ($HostInfo->"resolve") ] > 0) (", " . $HostInfo->"resolve") ]); - - :if ($HostInfo->"notify" = true && $HostInfo->"disabled" != true) do={ - :local Name [ $EitherOr ($HostInfo->"name") ($HostVal->"name") ]; - - :local Metric { "count-down"=0; "count-up"=0; "notified"=false; "resolve-failcnt"=0 }; - :if ([ :typeof ($NetwatchNotify->$Name) ] = "array") do={ - :set $Metric ($NetwatchNotify->$Name); - } - - :if ([ :typeof ($HostInfo->"resolve") ] = "str") do={ - :if ([ $IsDNSResolving ] = true) do={ - :do { - :local Resolve [ :resolve type=[ $IfThenElse ([ :typeof ($HostVal->"host") ] = "ip") \ - "ipv4" "ipv6" ] ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - :if ([ $ResolveExpected $ScriptName ($HostInfo->"resolve") ($HostVal->"host") ] = false) do={ - $LogPrint info $ScriptName ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating."); - /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failcnt") 0; - :set ($HostVal->"status") "unknown"; - } - } - } on-error={ - :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3) do={ - $LogPrint [ $IfThenElse ($HostInfo->"no-resolve-fail" != true) warning debug ] \ - $ScriptName ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed."); - } - } - } - } - - :if ($HostVal->"status" = "up") do={ - :local CountDown ($Metric->"count-down"); - :if ($CountDown > 0) do={ - $LogPrint info $ScriptName \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up."); - :set ($Metric->"count-down") 0; - } - :set ($Metric->"count-up") ($Metric->"count-up" + 1); - :if ($Metric->"notified" = true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is up since " . $HostVal->"since" . ".\n" . \ - "It was down for " . $CountDown . " checks since " . ($Metric->"since") . "."); - :if ([ :typeof ($HostInfo->"note") ] = "str") do={ - :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); - } - :if ([ :typeof ($HostInfo->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $ScriptName $Name $Type "up" \ - ($HostInfo->"up-hook") ]); - } - $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . $Name . " up"); \ - message=$Message; link=($HostInfo->"link") }); - } - :set ($Metric->"notified") false; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since"); - } - - :if ($HostVal->"status" = "down") do={ - :set ($Metric->"count-down") ($Metric->"count-down" + 1); - :set ($Metric->"count-up") 0; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since") ($HostVal->"since"); - :local CountDown [ $IfThenElse ([ :tonum ($HostInfo->"count") ] > 0) ($HostInfo->"count") 5 ]; - :local Parent ($HostInfo->"parent"); - :local ParentUp false; - :while ([ :len $Parent ] > 0) do={ - :set CountDown ($CountDown + 1); - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - :set Parent ($HostInfo->"parent"); - :local ParentNotified false; - :while ($ParentNotified = false && [ :len $Parent ] > 0) do={ - :set ParentNotified [ $IfThenElse (($NetwatchNotify->$Parent->"notified") = true) \ - true false ]; - :set ParentUp ($NetwatchNotify->$Parent->"count-up"); - :if ($ParentNotified = false) do={ - :set Parent ($NetwatchNotify->$Parent->"parent"); - } - } - :if ($Metric->"notified" = false || $Metric->"count-down" % 120 = 0 || \ - $ScriptFromTerminalCached = true) do={ - $LogPrint [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $ScriptName \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is down for " . \ - $Metric->"count-down" . " checks, " . [ $IfThenElse ($ParentNotified = false) [ $IfThenElse \ - ($Metric->"notified" = true) ("already notified.") ($CountDown - $Metric->"count-down" . \ - " to go.") ] ("parent " . $Type . " " . $Parent . " is down.") ]); - } - :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ - [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $ScriptName $Name $Type "pre-down" ($HostInfo->"pre-down-hook"); - } - :if ($ParentNotified = false && $Metric->"count-down" >= $CountDown && \ - ($ParentUp = false || $ParentUp > 2) && $Metric->"notified" != true) do={ - :local Message ("The " . $Type . " '" . $Name . "' (" . $HostDetails . \ - ") is down since " . $HostVal->"since" . "."); - :if ([ :typeof ($HostInfo->"note") ] = "str") do={ - :set Message ($Message . "\n\nNote:\n" . ($HostInfo->"note")); - } - :if ([ :typeof ($HostInfo->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $ScriptName $Name $Type "down" \ - ($HostInfo->"down-hook") ]); - } - :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=[ $EitherOr ($HostInfo->"origin") $ScriptName ]; silent=($HostInfo->"silent"); \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . $Name . " down"); \ - message=$Message; link=($HostInfo->"link") }); - } - :set ($Metric->"notified") true; - } - } - - :set ($NetwatchNotify->$Name) { - "count-down"=($Metric->"count-down"); - "count-up"=($Metric->"count-up"); - "notified"=($Metric->"notified"); - "parent"=($Metric->"parent"); - "resolve-failcnt"=($Metric->"resolve-failcnt"); - "since"=($Metric->"since") }; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/netwatch-syslog b/netwatch-syslog new file mode 100644 index 0000000..f274c18 --- /dev/null +++ b/netwatch-syslog @@ -0,0 +1,17 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-syslog +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires: dont-require-permissions=yes +# +# manage remote logging facilities +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-syslog.md + +:local Remote [ /system logging action get ([ find where target=remote ]->0) remote ]; + +if ([ / tool netwatch get [ find where host=$Remote up-script="netwatch-syslog" down-script="netwatch-syslog" ] status ] = "up") do={ + / system logging set disabled=no [ find where action=remote disabled=yes ]; +} else={ + / system logging set disabled=yes [ find where action=remote disabled=no ]; +} diff --git a/news-and-changes.rsc b/news-and-changes.rsc deleted file mode 100644 index 459326f..0000000 --- a/news-and-changes.rsc +++ /dev/null @@ -1,72 +0,0 @@ -# News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md - -:global IDonate; - -:global IfThenElse; -:global RequiredRouterOS; -:global SymbolForNotification; - -:local Resource [ /system/resource/get ]; - -# News, changes and migration up to change 95: -# https://git.eworm.de/cgit/routeros-scripts/plain/global-config.changes?h=change-95 - -# Changes for global-config to be added to notification on script updates -:global GlobalConfigChanges { - 96="Added support for notes in 'netwatch-notify', these are included verbatim into the notification."; - 97="Modified 'dhcp-to-dns' to always add A records for names with mac address, and optionally add CNAME records if the host name is available."; - 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; - 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; - 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; - 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; - 102="Modified 'hotspot-to-wpa' to support non-local (radius) users."; - 103="Dropped hard-coded name and timeout from 'hotspot-to-wpa-cleanup', instead a comment is required for dhcp server now."; - 104="All relevant scripts were ported to new wifiwave2 and are available for AX devices now!"; - 105="Extended 'check-routeros-update' to support automatic update from specific neighbor(s)."; - 106="Modified 'telegram-chat' to make it act on message replies, without activation. Also made it answer a single question mark with a short notice."; - 107="Dropped support for non-fixed width font in Telegram notifications."; - 108="Enhanced 'log-forward' to list log messages with colorful bullets to indicate severity."; - 109="Added support to send notifications via Ntfy (ntfy.sh)."; - 110="Dropped support for loading scripts from local storage."; - 111="Modified 'dhcp-to-dns' to allow multiple records for one mac address."; - 112="Enhanced 'mod/ssh-keys-import' to record the fingerprint of keys."; - 113="Added helper functions for easier setup to Matrix notification module."; - 114="All relevant scripts were ported to new wifi package for RouterOS 7.13 and later. Migration is complex and thus not done automatically!"; - 115=("Celebrating " . [ $SymbolForNotification "sparkles,star" ] . "1.000 stars " . [ $SymbolForNotification "star,sparkles" ] . "on Github! Please continue starring..."); - 116=("... and also please keep in mind that it takes a huge amount of time maintaining these scripts. " . [ $IfThenElse ($IDonate != true) \ - ("Following the donation hint " . [ $SymbolForNotification "arrow-down" "below" ] . "to keep me motivated is much appreciated. Thanks!") \ - ("Looks like you did donate already. " . [ $SymbolForNotification "heart" "<3" ] . "Much appreciated, thanks!") ]); - 117="Enhanced 'packages-update' to support deferred reboot on automatically installed updates."; - 118=("RouterOS packages increase in size with each release. This becomes a problem for devices with 16MB storage and below. " . \ - [ $IfThenElse ($Resource->"total-hdd-space" < 16000000) ("Your " . $Resource->"board-name" . " is specifically affected! ") \ - [ $IfThenElse ($Resource->"free-hdd-space" > 4000000) ("(Your " . $Resource->"board-name" . " does not suffer this issue.) ") ] ] . \ - "Huge configuration and lots of scripts give an extra risk. Take care!"); - 119="Added support for IPv6 to script 'fw-addr-lists'."; - 120="Implemented a workaround in 'backup-cloud'. Now script should no longer just crash, but send notification with error."; - 121="The 'wifiwave2' scripts are finally gone. Development continues with 'wifi' in RouterOS 7.13 and later."; - 122="The global configuration was enhanced to support loading snippets. Configuration can be split off to scripts where name starts with 'global-config-overlay.d/'."; - 123="Introduced new function '\$LogPrint', and deprecated '\$LogPrintExit2'. Please update custom scripts if you use it."; - 124="Added support for links in 'netwatch-notify', these are added below the formatted notification text."; - 125=("April's Fool! " . [ $SymbolForNotification "smiley-partying-face" ] . "Well, you missed it... - no charge nor fees. (Anyway... Donations are much appreciated, " . [ $SymbolForNotification "smiley-smiling-face" ] . "thanks!)"); - 126="Made 'telegram-chat' capable of handling large command output. Telegram messages still limit the size, so it is truncated now."; - 127="Added support for authentication to Ntfy notification module."; - 128="Added another list from blocklist.de to default configuration for 'fw-addr-lists'."; - 129="Extended 'backup-partition' to support RouterOS copy-over - interactively or before feature update."; - 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 -:global GlobalConfigMigration { - 97=":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; }"; - 100=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"ssh-keys-import\" source~\"^#!rsc by RouterOS\\r?\\n\" ] ] > 0) do={ /system/script/set name=\"mod/ssh-keys-import\" ssh-keys-import; \$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; }"; - 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={ }; }; }"; -}; diff --git a/ospf-to-leds b/ospf-to-leds new file mode 100644 index 0000000..b899b50 --- /dev/null +++ b/ospf-to-leds @@ -0,0 +1,24 @@ +#!rsc by RouterOS +# RouterOS script: ospf-to-leds +# Copyright (c) 2020-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# visualize ospf instance state via leds +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md + +:global LogPrintExit; +:global ParseKeyValueStore; + +:foreach Instance in=[ / routing ospf instance find where comment~"^ospf-to-leds," ] do={ + :local InstanceVal [ / routing ospf instance get $Instance ]; + :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); + :local LEDType [ / system leds get [ find where leds=$LED ] type ]; + + $LogPrintExit debug ("OSPF instance " . $InstanceVal->"name" . " is " . $InstanceVal->"state" . ".") false; + :if ($InstanceVal->"state" = "running" && $LEDType = "off") do={ + / system leds set type=on [ find where leds=$LED ]; + } + :if ($InstanceVal->"state" = "down" && $LEDType = "on") do={ + / system leds set type=off [ find where leds=$LED ]; + } +} diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc deleted file mode 100644 index a8662b3..0000000 --- a/ospf-to-leds.rsc +++ /dev/null @@ -1,49 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ospf-to-leds -# Copyright (c) 2020-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# visualize ospf instance state via leds -# https://rsc.eworm.de/doc/ospf-to-leds.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :foreach Instance in=[ /routing/ospf/instance/find where comment~"^ospf-to-leds," ] do={ - :local InstanceVal [ /routing/ospf/instance/get $Instance ]; - :local LED ([ $ParseKeyValueStore ($InstanceVal->"comment") ]->"leds"); - :local LEDType [ /system/leds/get [ find where leds=$LED ] type ]; - - :local NeighborCount 0; - :foreach Area in=[ /routing/ospf/area/find where instance=($InstanceVal->"name") ] do={ - :local AreaName [ /routing/ospf/area/get $Area name ]; - :set NeighborCount ($NeighborCount + [ :len [ /routing/ospf/neighbor/find where area=$AreaName ] ]); - } - - :if ($NeighborCount > 0 && $LEDType = "off") do={ - $LogPrint info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!"); - /system/leds/set type=on [ find where leds=$LED ]; - } - :if ($NeighborCount = 0 && $LEDType = "on") do={ - $LogPrint info $ScriptName ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!"); - /system/leds/set type=off [ find where leds=$LED ]; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/packages-update b/packages-update new file mode 100644 index 0000000..022a110 --- /dev/null +++ b/packages-update @@ -0,0 +1,89 @@ +#!rsc by RouterOS +# RouterOS script: packages-update +# Copyright (c) 2019-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download packages and reboot for installation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md + +:global DownloadPackage; +:global LogPrintExit; +:global ScriptFromTerminal; +:global ScriptLock; +:global VersionToNum; + +$ScriptLock "packages-update"; + +:local Update [ / system package update get ]; + +:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ + $LogPrintExit warning "Latest version is not known." true; +} + +:if ($Update->"installed-version" = $Update->"latest-version") do={ + $LogPrintExit info ("Version " . $Update->"latest-version" . " is already installed.") true; +} + +:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; +:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + +:local DoDowngrade false; +:if ($NumInstalled > $NumLatest) do={ + :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :put "Latest version is older than installed one. Want to downgrade? [y/N]"; + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + :set DoDowngrade true; + } else={ + :put "Canceled..."; + } + } else={ + $LogPrintExit warning ("Not installing downgrade automatically.") true; + } +} + +:foreach Package in=[ / system package find where !bundle ] do={ + :local PkgName [ / system package get $Package name ]; + if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ + $LogPrintExit error ("Download for package " . $PkgName . " failed.") true; + } +} + +:foreach Script in=[ / system script find where name~"^(cloud|email|upload)-backup\$" ] do={ + :local ScriptName [ / system script get $Script name ]; + :do { + $LogPrintExit info ("Running backup script " . $ScriptName . " before update.") false; + / system script run $Script; + } on-error={ + $LogPrintExit warning ("Running backup script " . $ScriptName . " before update failed!") false; + :if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :put "Do you want to continue anyway? [y/N]"; + :if (([ :terminal inkey timeout=60 ] % 32) = 25) do={ + $LogPrintExit info ("User requested to continue anyway.") false; + } else={ + $LogPrintExit info ("Canceled update...") true; + } + } else={ + $LogPrintExit info ("Canceled non-interactive update.") true; + } + } +} + +:if ($DoDowngrade = true) do={ + $LogPrintExit info ("Rebooting for downgrade.") false; + :delay 1s; + / system package downgrade; +} + +:if ([ $ScriptFromTerminal "packages-update" ] = true) do={ + :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; + :if (([ :terminal inkey timeout=60 ] % 32) = 19) do={ + / system scheduler add name="reboot-for-update" start-time=03:00:00 interval=1d \ + on-event=(":global RandomDelay; \$RandomDelay 3600; " . \ + "/ system scheduler remove reboot-for-update; / system reboot;"); + $LogPrintExit info ("Scheduled reboot for update between 03:00 and 04:00.") true; + } +} + +$LogPrintExit info ("Rebooting for update.") false; +:delay 1s; +/ system reboot; diff --git a/packages-update.rsc b/packages-update.rsc deleted file mode 100644 index b11596e..0000000 --- a/packages-update.rsc +++ /dev/null @@ -1,168 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: packages-update -# Copyright (c) 2019-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, scheduler -# -# download packages and reboot for installation -# https://rsc.eworm.de/doc/packages-update.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global BackupRandomDelay; - :global PackagesUpdateDeferReboot; - :global PackagesUpdateBackupFailure; - - :global DownloadPackage; - :global Grep; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptFromTerminal; - :global ScriptLock; - :global VersionToNum; - - :local Schedule do={ - :local ScriptName [ :tostr $1 ]; - - :global GetRandomNumber; - :global LogPrint; - - :global RebootForUpdate do={ - /system/reboot; - } - - :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; - /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ - on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ - ":global RebootForUpdate; \$RebootForUpdate;"); - $LogPrint info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ")."); - :return true; - } - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={ - $LogPrint warning $ScriptName ("Running from backup partition, refusing to act."); - :set ExitOK true; - :error false; - } - - :local Update [ /system/package/update/get ]; - - :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrint warning $ScriptName ("Latest version is not known."); - :set ExitOK true; - :error false; - } - - :if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is already installed."); - :set ExitOK true; - :error true; - } - - :local RunOrder ({}); - :foreach Script in=[ /system/script/find where source~("\n# provides: backup-script\\b") ] do={ - :local ScriptVal [ /system/script/get $Script ]; - :local Store [ $ParseKeyValueStore [ $Grep ($ScriptVal->"source") ("\23 provides: backup-script, ") ] ]; - - :set ($RunOrder->($Store->"order" . "-" . $ScriptVal->"name")) ($ScriptVal->"name"); - } - - :local BackupRandomDelayBefore $BackupRandomDelay; - :foreach Order,Script in=$RunOrder do={ - :set BackupRandomDelay 0; - :set PackagesUpdateBackupFailure false; - :do { - $LogPrint info $ScriptName ("Running backup script " . $Script . " before update."); - /system/script/run $Script; - } on-error={ - :set PackagesUpdateBackupFailure true; - } - :set BackupRandomDelay $BackupRandomDelayBefore; - - :if ($PackagesUpdateBackupFailure = true) do={ - $LogPrint warning $ScriptName ("Running backup script " . $Script . " before update failed!"); - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put "Do you want to continue anyway? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $LogPrint info $ScriptName ("User requested to continue anyway."); - } else={ - $LogPrint info $ScriptName ("Canceled update..."); - :set ExitOK true; - :error false; - } - } else={ - $LogPrint warning $ScriptName ("Canceled non-interactive update."); - :set ExitOK true; - :error false; - } - } - } - - :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; - :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; - - :local DoDowngrade false; - :if ($NumInstalled > $NumLatest) do={ - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put "Latest version is older than installed one. Want to downgrade? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - :set DoDowngrade true; - } else={ - :put "Canceled..."; - } - } else={ - $LogPrint warning $ScriptName ("Not installing downgrade automatically."); - :set ExitOK true; - :error false; - } - } - - :foreach Package in=[ /system/package/find where !bundle !available ] do={ - :local PkgName [ /system/package/get $Package name ]; - :if ([ $DownloadPackage $PkgName ($Update->"latest-version") ] = false) do={ - $LogPrint error $ScriptName ("Download for package " . $PkgName . " failed, update aborted."); - :set ExitOK true; - :error false; - } - } - - :if ($DoDowngrade = true) do={ - $LogPrint info $ScriptName ("Rebooting for downgrade."); - :delay 1s; - /system/package/downgrade; - } - - :if ([ $ScriptFromTerminal $ScriptName ] = true) do={ - :put "Do you want to (s)chedule reboot or (r)eboot now? [s/R]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 19) do={ - $Schedule $ScriptName; - :set ExitOK true; - :error true; - } - } else={ - :if ($PackagesUpdateDeferReboot = true) do={ - $Schedule $ScriptName; - :set ExitOK true; - :error true; - } - } - - $LogPrint info $ScriptName ("Rebooting for update."); - :delay 1s; - /system/reboot; -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/ppp-on-up b/ppp-on-up new file mode 100644 index 0000000..9de01b8 --- /dev/null +++ b/ppp-on-up @@ -0,0 +1,31 @@ +#!rsc by RouterOS +# RouterOS script: ppp-on-up +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run scripts on ppp up +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md + +:global LogPrintExit; + +:local Interface $interface; + +:if ([ :typeof $Interface ] = "nothing") do={ + $LogPrintExit error "This script is supposed to run from ppp on-up script hook." true; +} + +:local IntName [ / interface get $Interface name ]; +:log info ("PPP interface " . $IntName . " is up."); + +/ ipv6 dhcp-client release [ find where interface=$IntName !disabled ]; + +:local Scripts { + "update-tunnelbroker" +} + +:foreach Script in=$Scripts do={ + :if ([ :len [ / system script find where name=$Script ] ] > 0) do={ + :log debug ("Running script from ppp-on-up: " . $Script); + / system script run $Script; + } +} diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc deleted file mode 100644 index e09bd9d..0000000 --- a/ppp-on-up.rsc +++ /dev/null @@ -1,44 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ppp-on-up -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# run scripts on ppp up -# https://rsc.eworm.de/doc/ppp-on-up.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global LogPrint; - - :local Interface $interface; - - :if ([ :typeof $Interface ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from ppp on-up script hook."); - :set ExitOK true; - :error false; - } - - :local IntName [ /interface/get $Interface name ]; - $LogPrint info $ScriptName ("PPP interface " . $IntName . " is up."); - - /ipv6/dhcp-client/release [ find where interface=$IntName !disabled bound ]; - - :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\r?\n") ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrint debug $ScriptName ("Running script: " . $ScriptName); - /system/script/run $Script; - } on-error={ - $LogPrint warning $ScriptName ("Running script '" . $ScriptName . "' failed!"); - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/rotate-ntp b/rotate-ntp new file mode 100644 index 0000000..a0cc524 --- /dev/null +++ b/rotate-ntp @@ -0,0 +1,28 @@ +#!rsc by RouterOS +# RouterOS script: rotate-ntp +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# rotate the ntp servers +# https://git.eworm.de/cgit/routeros-scripts/about/doc/rotate-ntp.md + +:global NtpPool; + +:global LogPrintExit; + +:local Ntp1; +:local Ntp2; + +:if ([ / system ntp client get enabled ] != true) do={ + $LogPrintExit warning "NTP client is not enabled!" true; +} + +:do { + :set Ntp1 [ :resolve ("0." . $NtpPool) ]; + :set Ntp2 [ :resolve ("1." . $NtpPool) ]; +} on-error={ + $LogPrintExit warning "Resolving NTP server failed." true; +} + +$LogPrintExit info ("Updating NTP servers to " . $Ntp1 . " and " . $Ntp2) false; +/ system ntp client set primary-ntp=$Ntp1 secondary-ntp=$Ntp2; diff --git a/script-updates b/script-updates new file mode 100644 index 0000000..be79f58 --- /dev/null +++ b/script-updates @@ -0,0 +1,6 @@ +#!rsc by RouterOS +# RouterOS script: script-updates + +:global LogPrintExit; + +$LogPrintExit warning ("This script has been replaced by function '\$ScriptInstallUpdate'.") true; diff --git a/sms-action b/sms-action new file mode 100644 index 0000000..a070cc9 --- /dev/null +++ b/sms-action @@ -0,0 +1,24 @@ +#!rsc by RouterOS +# RouterOS script: sms-action +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# run action on received SMS +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md + +:global SmsAction; + +:global LogPrintExit; + +:local Action $action; + +:if ([ :typeof $Action ] = "nothing") do={ + $LogPrintExit error "This script is supposed to run from SMS hook with action=..." true; +} + +:local Code ($SmsAction->$Action); +:local Parsed [ :parse $Code ]; + +:log info ("Acting on SMS action '" . $Action . "': " . $Code); +:delay 1s; +$Parsed; diff --git a/sms-action.rsc b/sms-action.rsc deleted file mode 100644 index 3c8307a..0000000 --- a/sms-action.rsc +++ /dev/null @@ -1,41 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: sms-action -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# run action on received SMS -# https://rsc.eworm.de/doc/sms-action.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global SmsAction; - - :global LogPrint; - :global ValidateSyntax; - - :local Action $action; - - :if ([ :typeof $Action ] = "nothing") do={ - $LogPrint error $ScriptName ("This script is supposed to run from SMS hook with action=..."); - :set ExitOK true; - :error false; - } - - :local Code ($SmsAction->$Action); - :if ([ $ValidateSyntax $Code ] = true) do={ - :log info ("Acting on SMS action '" . $Action . "': " . $Code); - :delay 1s; - [ :parse $Code ]; - } else={ - $LogPrint warning $ScriptName ("The code for action '" . $Action . "' failed syntax validation!"); - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/sms-forward b/sms-forward new file mode 100644 index 0000000..96a001d --- /dev/null +++ b/sms-forward @@ -0,0 +1,62 @@ +#!rsc by RouterOS +# RouterOS script: sms-forward +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# forward SMS to e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md + +:global Identity; + +:global IfThenElse; +:global LogPrintExit; +:global MailServerIsUp; +:global ScriptLock; +:global SendNotification; +:global SymbolForNotification; +:global WaitFullyConnected; + +$ScriptLock "sms-forward"; + +:if ([ / tool sms get receive-enabled ] = false) do={ + $LogPrintExit warning "Receiving of SMS is not enabled." true; +} + +$WaitFullyConnected; + +:if ([ $MailServerIsUp ] = false) do={ + $LogPrintExit warning "Mail server is not up." true; +} + +:local Settings [ / tool sms get ]; + +# forward SMS in a loop +:while ([ :len [ / tool sms inbox find ] ] > 0) do={ + :local Phone [ / tool sms inbox get ([ find ]->0) phone ]; + :local Messages ""; + :local Delete [ :toarray "" ]; + + :foreach Sms in=[ / tool sms inbox find where phone=$Phone ] do={ + :local SmsVal [ / tool sms inbox get $Sms ]; + + :if ($Phone = $Settings->"allowed-number" && \ + ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ + $LogPrintExit debug ("Removing SMS, which started a script.") false; + / tool sms inbox remove $Sms; + } else={ + :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ + " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); + :set Delete ($Delete, $Sms); + } + } + + :if ([ :len $Messages ] > 0) do={ + :local Count [ :len $Delete ]; + $SendNotification ([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone) \ + ("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ + " by " . $Identity . " from " . $Phone . ":" . $Messages); + :foreach Sms in=$Delete do={ + / tool sms inbox remove $Sms; + } + } +} diff --git a/sms-forward.rsc b/sms-forward.rsc deleted file mode 100644 index 8169022..0000000 --- a/sms-forward.rsc +++ /dev/null @@ -1,101 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: sms-forward -# Copyright (c) 2013-2025 Christian Hesse -# Anatoly Bubenkov -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# forward SMS to e-mail -# https://rsc.eworm.de/doc/sms-forward.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - :global SmsForwardHooks; - - :global IfThenElse; - :global LogPrint; - :global LogPrintOnce; - :global ScriptLock; - :global SendNotification2; - :global SymbolForNotification; - :global ValidateSyntax; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled."); - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :local Settings [ /tool/sms/get ]; - - :if ([ /interface/lte/get ($Settings->"port") running ] != true) do={ - $LogPrint info $ScriptName ("The LTE interface is not in running state, skipping."); - :set ExitOK true; - :error true; - } - - # forward SMS in a loop - :while ([ :len [ /tool/sms/inbox/find ] ] > 0) do={ - :local Phone [ /tool/sms/inbox/get ([ find ]->0) phone ]; - :local Messages ""; - :local Delete ({}); - - :foreach Sms in=[ /tool/sms/inbox/find where phone=$Phone ] do={ - :local SmsVal [ /tool/sms/inbox/get $Sms ]; - - :if ($Phone = $Settings->"allowed-number" && \ - ($SmsVal->"message")~("^:cmd " . $Settings->"secret" . " script ")) do={ - $LogPrint debug $ScriptName ("Removing SMS, which started a script."); - /tool/sms/inbox/remove $Sms; - } else={ - :set Messages ($Messages . "\n\nOn " . $SmsVal->"timestamp" . \ - " type " . $SmsVal->"type" . ":\n" . $SmsVal->"message"); - :foreach Hook in=$SmsForwardHooks do={ - :if ($Phone~($Hook->"allowed-number") && ($SmsVal->"message")~($Hook->"match")) do={ - :if ([ $ValidateSyntax ($Hook->"command") ] = true) do={ - $LogPrint info $ScriptName ("Running hook '" . $Hook->"match" . "': " . $Hook->"command"); - :do { - :local Command [ :parse ($Hook->"command") ]; - $Command Phone=$Phone Message=($SmsVal->"message"); - :set Messages ($Messages . "\n\nRan hook '" . $Hook->"match" . "':\n" . $Hook->"command"); - } on-error={ - $LogPrint warning $ScriptName ("The code for hook '" . $Hook->"match" . "' failed to run!"); - } - } else={ - $LogPrint warning $ScriptName ("The code for hook '" . $Hook->"match" . "' failed syntax validation!"); - } - } - } - :set Delete ($Delete, $Sms); - } - } - - :if ([ :len $Messages ] > 0) do={ - :local Count [ :len $Delete ]; - $SendNotification2 ({ origin=$ScriptName; \ - subject=([ $SymbolForNotification "incoming-envelope" ] . "SMS Forwarding from " . $Phone); \ - message=("Received " . [ $IfThenElse ($Count = 1) "this message" ("these " . $Count . " messages") ] . \ - " by " . $Identity . " from " . $Phone . ":" . $Messages) }); - :foreach Sms in=$Delete do={ - /tool/sms/inbox/remove $Sms; - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/ssh-keys-import b/ssh-keys-import new file mode 100644 index 0000000..1f158fd --- /dev/null +++ b/ssh-keys-import @@ -0,0 +1,11 @@ +#!rsc by RouterOS +# RouterOS script: ssh-keys-import +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# import ssh keys from file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ssh-keys-import.md + +:foreach Key in=[ / file find where type="ssh key" ] do={ + / user ssh-key import user=admin public-key-file=[ / file get $Key name ]; +} diff --git a/super-mario-theme.rsc b/super-mario-theme similarity index 94% rename from super-mario-theme.rsc rename to super-mario-theme index 726c526..e13c934 100644 --- a/super-mario-theme.rsc +++ b/super-mario-theme @@ -1,10 +1,10 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme -# https://rsc.eworm.de/doc/super-mario-theme.md +# https://git.eworm.de/cgit/routeros-scripts/about/doc/super-mario-theme.md :local Beeps { { 660; 100 }; 150; { 660; 100 }; 300; { 660; 100 }; 300; diff --git a/telegram-chat.rsc b/telegram-chat.rsc deleted file mode 100644 index 5db4860..0000000 --- a/telegram-chat.rsc +++ /dev/null @@ -1,195 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: telegram-chat -# Copyright (c) 2023-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, fetch -# -# use Telegram to chat with your Router and send commands -# https://rsc.eworm.de/doc/telegram-chat.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global Identity; - :global TelegramChatActive; - :global TelegramChatGroups; - :global TelegramChatId; - :global TelegramChatIdsTrusted; - :global TelegramChatOffset; - :global TelegramChatRunTime; - :global TelegramMessageIDs; - :global TelegramRandomDelay; - :global TelegramTokenId; - - :global CertificateAvailable; - :global EitherOr; - :global EscapeForRegEx; - :global GetRandom20CharAlNum; - :global IfThenElse; - :global LogPrint; - :global MAX; - :global MIN; - :global MkDir; - :global RandomDelay; - :global RmDir; - :global ScriptLock; - :global SendTelegram2; - :global SymbolForNotification; - :global ValidateSyntax; - :global WaitForFile; - :global WaitFullyConnected; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - $WaitFullyConnected; - - :if ([ :typeof $TelegramChatOffset ] != "array") do={ - :set TelegramChatOffset { 0; 0; 0 }; - } - :if ([ :typeof $TelegramRandomDelay ] != "num") do={ - :set TelegramRandomDelay 0; - } - - :if ([ $CertificateAvailable "Go Daddy Root Certificate Authority - G2" ] = false) do={ - $LogPrint warning $ScriptName ("Downloading required certificate failed."); - :set ExitOK true; - :error false; - } - - $RandomDelay $TelegramRandomDelay; - - :local Data false; - :for I from=1 to=4 do={ - :if ($Data = false) do={ - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \ - ("https://api.telegram.org/bot" . $TelegramTokenId . "/getUpdates?offset=" . \ - $TelegramChatOffset->0 . "&allowed_updates=%5B%22message%22%5D") as-value ]->"data"); - :set TelegramRandomDelay [ $MAX 0 ($TelegramRandomDelay - 1) ]; - } on-error={ - :if ($I < 4) do={ - $LogPrint debug $ScriptName ("Fetch failed, " . $I . ". try."); - :set TelegramRandomDelay [ $MIN 15 ($TelegramRandomDelay + 5) ]; - :delay (($I * $I) . "s"); - } - } - } - } - - :if ($Data = false) do={ - $LogPrint warning $ScriptName ("Failed getting updates."); - :set ExitOK true; - :error false; - } - - :local JSON [ :deserialize from=json value=$Data ]; - :local UpdateID 0; - :local Uptime [ /system/resource/get uptime ]; - :foreach Update in=($JSON->"result") do={ - :set UpdateID ($Update->"update_id"); - :local Message ($Update->"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={ - :set Trusted true; - } - } - - :if ($Trusted = true) do={ - :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"); threadid=$ThreadId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - 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={ - :if ($Command ~ ("^! *(" . [ $EscapeForRegEx $Identity ] . "|@" . $TelegramChatGroups . ")\$")) do={ - :set TelegramChatActive true; - } else={ - :set TelegramChatActive false; - } - $LogPrint info $ScriptName ("Now " . [ $IfThenElse $TelegramChatActive "active" "passive" ] . \ - " from update " . $UpdateID . "!"); - :set Done true; - } - :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 ]); - :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ - $LogPrint error $ScriptName ("Failed creating directory!"); - :set ExitOK true; - :error false; - } - $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Command); - :execute script=(":do {\n" . $Command . "\n} on-error={ /file/add name=\"" . $File . ".failed\" };" . \ - "/file/add name=\"" . $File . ".done\"") file=($File . "\00"); - :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ - :set State ([ $SymbolForNotification "warning-sign" ] . "The command did not finish, still running in background.\n\n"); - } - :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ - :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"); threadid=$ThreadId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ - $State . [ $IfThenElse ([ :len $Content ] > 0) \ - ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) \ - ([ $SymbolForNotification "memo" ] . "No output.") ]) }); - $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"); threadid=$ThreadId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Command . "\n\n" . \ - [ $SymbolForNotification "cross-mark" ] . "The command failed syntax validation!") }); - } - } - } else={ - :local MessageText ("Received a message from untrusted contact " . \ - [ $IfThenElse ([ :len ($From->"username") ] = 0) "without username" ("'" . $From->"username" . "'") ] . \ - " (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"); threadid=$ThreadId; \ - subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ - message=("You are not trusted.") }); - } else={ - $LogPrint info $ScriptName $MessageText; - } - } - } else={ - $LogPrint debug $ScriptName ("Already handled update " . $UpdateID . "."); - } - } - :set TelegramChatOffset ([ :pick $TelegramChatOffset 1 3 ], \ - [ $IfThenElse ($UpdateID >= $TelegramChatOffset->2) ($UpdateID + 1) ($TelegramChatOffset->2) ]); -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade new file mode 100644 index 0000000..cb8f87e --- /dev/null +++ b/unattended-lte-firmware-upgrade @@ -0,0 +1,33 @@ +#!rsc by RouterOS +# RouterOS script: unattended-lte-firmware-upgrade +# Copyright (c) 2018-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# schedule unattended lte firmware upgrade +# https://git.eworm.de/cgit/routeros-scripts/about/doc/unattended-lte-firmware-upgrade.md + +:foreach Interface in=[ / interface lte find ] do={ + :local Firmware; + :local IntName [ / interface lte get $Interface name ]; + :do { + :set Firmware [ / interface lte firmware-upgrade $Interface once as-value ]; + } on-error={ + :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); + } + + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); + :global LTEFirmwareUpgrade do={ + :global LTEFirmwareUpgrade; + :set LTEFirmwareUpgrade; + / system scheduler remove ($1 . "-firmware-upgrade"); + / interface lte firmware-upgrade $1 upgrade=yes; + :log info ("LTE firmware upgrade finished, waiting for installation before reset."); + :delay 150s; + / interface lte at-chat $1 input="AT+RESET"; + :log info ("Reset device, waiting to finish and reconnect."); + } + / system scheduler add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ + on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); + } +} diff --git a/unattended-lte-firmware-upgrade.rsc b/unattended-lte-firmware-upgrade.rsc deleted file mode 100644 index 83925fd..0000000 --- a/unattended-lte-firmware-upgrade.rsc +++ /dev/null @@ -1,52 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# requires device-mode, scheduler -# -# schedule unattended lte firmware upgrade -# https://rsc.eworm.de/doc/unattended-lte-firmware-upgrade.md - -:foreach Interface in=[ /interface/lte/find where running ] do={ - :local Firmware; - :local IntName [ /interface/lte/get $Interface name ]; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface as-value ]; - } on-error={ - :log debug ("Could not get latest LTE firmware version for interface " . $IntName . "."); - } - - :if ([ :typeof $Firmware ] = "array") do={ - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log info ("Scheduling LTE firmware upgrade for interface " . $IntName . "."); - - :global LTEFirmwareUpgrade do={ - :global LTEFirmwareUpgrade; - :set LTEFirmwareUpgrade; - - /system/scheduler/remove ($1 . "-firmware-upgrade"); - :do { - /interface/lte/firmware-upgrade $1 upgrade=yes; - :log info ("LTE firmware upgrade on '" . $1 . "' finished, waiting for reset."); - :delay 240s; - :local Firmware [ /interface/lte/firmware-upgrade $1 as-value ]; - :if ([ :len ($Firmware->"latest") ] > 0 && \ - ($Firmware->"installed") != ($Firmware->"latest")) do={ - :log warning ("LTE firmware versions still differ. Upgrade failed anyway?"); - } - } on-error={ - :log error ("LTE firmware upgrade on '" . $1 . "' failed."); - } - } - - /system/scheduler/add name=($IntName . "-firmware-upgrade") start-time=startup interval=2s \ - on-event=(":global LTEFirmwareUpgrade; \$LTEFirmwareUpgrade \"" . $IntName . "\";"); - } else={ - :log info ("The LTE firmware is up to date on interface " . $IntName . "."); - } - } else={ - :log info ("No LTE firmware information available for interface " . $IntName . "."); - } -} diff --git a/update-gre-address b/update-gre-address new file mode 100644 index 0000000..7dd4896 --- /dev/null +++ b/update-gre-address @@ -0,0 +1,27 @@ +#!rsc by RouterOS +# RouterOS script: update-gre-address +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update gre interface remote address with dynamic address from +# ipsec remote peer +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-gre-address.md + +:global LogPrintExit; + +/ interface gre set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; + +:foreach Peer in=[ / ip ipsec active-peers find ] do={ + :local PeerVal [ / ip ipsec active-peers get $Peer ]; + :local GreInt [ / interface gre find where comment=$PeerVal->"id" ]; + :if ([ :len $GreInt ] > 0) do={ + :local GreIntVal [ / interface gre get $GreInt ]; + :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ + ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ + $GreIntVal->"disabled" = true)) do={ + $LogPrintExit info ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address") false; + / interface gre set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; + / interface gre set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; + } + } +} diff --git a/update-gre-address.rsc b/update-gre-address.rsc deleted file mode 100644 index cddfa92..0000000 --- a/update-gre-address.rsc +++ /dev/null @@ -1,46 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: update-gre-address -# Copyright (c) 2013-2025 Christian Hesse -# https://rsc.eworm.de/COPYING.md -# -# requires RouterOS, version=7.15 -# -# update gre interface remote address with dynamic address from -# ipsec remote peer -# https://rsc.eworm.de/doc/update-gre-address.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CharacterReplace; - :global LogPrint; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where !running !disabled ]; - - :foreach Peer in=[ /ip/ipsec/active-peers/find ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local GreInt [ /interface/gre/find where comment=($PeerVal->"id") or comment=[ $CharacterReplace ($PeerVal->"id") "CN=" "" ] ]; - :if ([ :len $GreInt ] > 0) do={ - :local GreIntVal [ /interface/gre/get $GreInt ]; - :if ([ :typeof ($PeerVal->"dynamic-address") ] = "str" && \ - ($PeerVal->"dynamic-address" != $GreIntVal->"remote-address" || \ - $GreIntVal->"disabled" = true)) do={ - $LogPrint info $ScriptName ("Updating remote address for interface " . $GreIntVal->"name" . " to " . $PeerVal->"dynamic-address"); - /interface/gre/set remote-address=0.0.0.0 disabled=yes [ find where remote-address=$PeerVal->"dynamic-address" name!=$GreIntVal->"name" ]; - /interface/gre/set $GreInt remote-address=($PeerVal->"dynamic-address") disabled=no; - } - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/update-tunnelbroker b/update-tunnelbroker new file mode 100644 index 0000000..d014178 --- /dev/null +++ b/update-tunnelbroker @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: update-tunnelbroker +# Copyright (c) 2013-2021 Christian Hesse +# Michael Gisbers +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# update local address of tunnelbroker interface +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md + +:global CertificateAvailable; +:global LogPrintExit; +:global ParseKeyValueStore; + +:if ([ / ip cloud get ddns-enabled ] != true) do={ + $LogPrintExit error "IP cloud DDNS is not enabled." true; +} + +# Get the current ip address from cloud +/ ip cloud force-update; +:while ([ / ip cloud get status ] != "updated") do={ + :delay 1s; +} +:local PublicAddress [ / ip cloud get public-address ]; + +:foreach Interface in=[ / interface 6to4 find where comment~"^tunnelbroker" !disabled ] do={ + :local InterfaceVal [ / interface 6to4 get $Interface ]; + + :if ($PublicAddress != $InterfaceVal->"local-address") do={ + :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; + + :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + $LogPrintExit error ("Downloading required certificate failed.") true; + } + $LogPrintExit info ("Local address changed, sending UPDATE to tunnelbroker! New address: " . $PublicAddress) false; + / tool fetch check-certificate=yes-without-crl \ + ("https://ipv4.tunnelbroker.net/nic/update\?hostname=" . $Comment->"id") \ + user=($Comment->"user") password=($Comment->"pass") output=none; + / interface 6to4 set $Interface local-address=$PublicAddress; + } else={ + $LogPrintExit debug ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; + } +} diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc deleted file mode 100644 index 45afa6f..0000000 --- a/update-tunnelbroker.rsc +++ /dev/null @@ -1,74 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2025 Christian Hesse -# Michael Gisbers -# https://rsc.eworm.de/COPYING.md -# -# provides: ppp-on-up -# requires RouterOS, version=7.15 -# requires device-mode, fetch -# -# update local address of tunnelbroker interface -# https://rsc.eworm.de/doc/update-tunnelbroker.md - -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local ExitOK false; -:do { - :local ScriptName [ :jobname ]; - - :global CertificateAvailable; - :global LogPrint; - :global ParseKeyValueStore; - :global ScriptLock; - - :if ([ $ScriptLock $ScriptName ] = false) do={ - :set ExitOK true; - :error false; - } - - :if ([ $CertificateAvailable "Starfield Root Certificate Authority - G2" ] = false) do={ - $LogPrint error $ScriptName ("Downloading required certificate failed."); - :set ExitOK true; - :error false; - } - - :foreach Interface in=[ /interface/6to4/find where comment~"^tunnelbroker" !disabled ] do={ - :local Data false; - :local InterfaceVal [ /interface/6to4/get $Interface ]; - :local Comment [ $ParseKeyValueStore ($InterfaceVal->"comment") ]; - - :for I from=2 to=0 do={ - :if ($Data = false) do={ - :do { - :set Data ([ /tool/fetch check-certificate=yes-without-crl \ - ("https://ipv4.tunnelbroker.net/nic/update?hostname=" . $Comment->"id") \ - user=($Comment->"user") password=($Comment->"pass") output=user as-value ]->"data"); - } on-error={ - $LogPrint debug $ScriptName ("Failed downloading, " . $I . " retries pending."); - :delay 2s; - } - } - } - - :if (!($Data ~ "^(good|nochg) ")) do={ - $LogPrint error $ScriptName ("Failed sending the local address to tunnelbroker or unexpected response!"); - :set ExitOK true; - :error false; - } - - :local PublicAddress [ :pick $Data ([ :find $Data " " ] + 1) [ :find $Data "\n" ] ]; - - :if ($PublicAddress != $InterfaceVal->"local-address") do={ - :if ([ :len [ /ip/address find where address~("^" . $PublicAddress . "/") ] ] < 1) do={ - $LogPrint warning $ScriptName ("The address " . $PublicAddress . " is not configured on your device. NAT by ISP?"); - } - - $LogPrint info $ScriptName ("Local address changed, updating tunnel configuration with address: " . $PublicAddress); - /interface/6to4/set $Interface local-address=$PublicAddress; - } - } -} on-error={ - :global ExitError; $ExitError $ExitOK [ :jobname ]; -} diff --git a/upload-backup b/upload-backup new file mode 100644 index 0000000..acb8399 --- /dev/null +++ b/upload-backup @@ -0,0 +1,79 @@ +#!rsc by RouterOS +# RouterOS script: upload-backup +# Copyright (c) 2013-2021 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# create and upload backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/upload-backup.md + +:global BackupPassword; +:global BackupSendBinary; +:global BackupSendExport; +:global BackupUploadPass; +:global BackupUploadUrl; +:global BackupUploadUser; +:global Domain; +:global Identity; + +:global CharacterReplace; +:global DeviceInfo; +:global IfThenElse; +:global LogPrintExit; +:global SendNotification; +:global SymbolForNotification; +:global WaitForFile; + +:if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrintExit error ("Configured to send neither backup nor config export.") true; +} + +# filename based on identity +:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; +:local BackupFile "none"; +:local ConfigFile "none"; +:local Failed 0; + +# binary backup +:if ($BackupSendBinary = true) do={ + / system backup save encryption=aes-sha256 name=$FileName password=$BackupPassword; + $WaitForFile ($FileName . ".backup"); + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".backup"); + :set BackupFile ($FileName . ".backup"); + } on-error={ + $LogPrintExit error ("Uploading backup file failed!") false; + :set BackupFile "failed"; + :set Failed 1; + } +} + +# create configuration export +:if ($BackupSendExport = true) do={ + / export terse file=$FileName; + $WaitForFile ($FileName . ".rsc"); + + :do { + / tool fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FileName . ".rsc"); + :set ConfigFile ($FileName . ".rsc"); + } on-error={ + $LogPrintExit error ("Uploading configuration export failed!") false; + :set ConfigFile "failed"; + :set Failed 1; + } +} + +$SendNotification [ $IfThenElse ($Failed > 0) \ + ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ + ([ $SymbolForNotification "floppy-disk" ] . "Backup & Config upload") ] \ + ("Backup and config export upload for " . $Identity . ".\n\n" . \ + [ $DeviceInfo ] . "\n\n" . \ + "Backup file: " . $BackupFile . "\n" . \ + "Config file: " . $ConfigFile) "" "" "true"; + +:if ($Failed = 1) do={ + :error "An error occured!"; +}