diff options
267 files changed, 9157 insertions, 4790 deletions
@@ -1,3 +1,13 @@ +# 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 new file mode 100644 index 0000000..0fdbdb4 --- /dev/null +++ b/BRANCHES.md @@ -0,0 +1,50 @@ +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.12-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 "url-suffix=?h=next"; + +## Switch existing script + +Alternatively switch an existing script to update from `next` branch: + + /system/script/set comment="url-suffix=?h=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 ScriptUpdatesUrlSuffix "?h=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/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 54b3228..dff933b 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -1,7 +1,14 @@ Past Contributions ================== -[◀ Go back to main README](README.md) +[![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.12-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) Thanks a lot for your contributions! ❤️ @@ -10,6 +17,7 @@ Thanks a lot for your contributions! ❤️ These persons contributed code or documentation. 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) * [Michael Gisbers](mailto:michael@gisbers.de) (@mgisbers) @@ -27,7 +35,11 @@ Add yourself to the list, * Christoph Boss (@Kampfwurst) * Devin Dean (@dd2594gh) * Evaldo Gardenal +* Giorgio Bikos +* Harold Schoemaker +* Hugo BV * Klaus Michael Rübsam +* Leonardo Valeri Manera * Linux-Schmie.de Michael Gisbers * Manuel Kuhn * Marek Čábák @@ -37,8 +49,9 @@ Add yourself to the list, * 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/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index e8be3e1..0de50ae 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -1,7 +1,14 @@ Initial commands ================ -[◀ Go back to main README](README.md) +[![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.12-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**: These command are inteneded for initial setup. If you are > not aware of the procedure please follow @@ -10,28 +17,39 @@ Initial commands Run the complete base installation: { - /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/R3.pem" dst-path="letsencrypt-R3.pem" as-value; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem" as-value; :delay 1s; - /certificate/import file-name=letsencrypt-R3.pem passphrase=""; - :if ([ :len [ /certificate/find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ] ] != 2) do={ + /certificate/import file-name=letsencrypt-E1.pem passphrase=""; + :if ([ :len [ /certificate/find where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470" ] ] != 2) do={ :error "Something is wrong with your certificates!"; }; - /file/remove "letsencrypt-R3.pem"; + /file/remove "letsencrypt-E1.pem"; :delay 1s; + /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ - /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/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; }"; :global CertificateNameByCN; - $CertificateNameByCN "R3"; - $CertificateNameByCN "ISRG Root X1"; + $CertificateNameByCN "E1"; + $CertificateNameByCN "ISRG Root X2"; }; -Optional to update the scripts automatically: +Then continue setup with +[scheduled automatic updates](README.md#scheduled-automatic-updates) or +[editing configuration](README.md#editing-configuration). + +## Fix existing installation - /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; +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. --- -[◀ Go back to main README](README.md) -[▲ Go back to top](#top) +[⬅️ Go back to main README](README.md) +[⬆️ Go back to top](#top) @@ -2,25 +2,33 @@ # template scripts -> final scripts # markdown files -> html files -TEMPLATE = $(wildcard *.template) -CAPSMAN = $(TEMPLATE:.template=.capsman) -LOCAL = $(TEMPLATE:.template=.local) +CAPSMAN = $(wildcard *.capsman.rsc) +LOCAL = $(wildcard *.local.rsc) +WIFI = $(wildcard *.wifi.rsc) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) HTML = $(MARKDOWN:.md=.html) -all: $(CAPSMAN) $(LOCAL) $(HTML) +all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML) %.html: %.md Makefile markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ -%.local: %.template Makefile - sed -e '/\/caps-man/d' -e 's|%PATH%|interface\/wireless|' -e 's|%TEMPL%|$(suffix $@)|' \ +%.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' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ < $< > $@ -%.capsman: %.template Makefile - sed -e '/\/interface\/wireless/d' -e 's/%PATH%/caps-man/' -e 's/%TEMPL%/$(suffix $@)/' \ +%.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' \ + -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!' \ < $< > $@ diff --git a/README.d/01-download-certs.avif b/README.d/01-download-certs.avif Binary files differindex 4da73fa..b27b23b 100644 --- a/README.d/01-download-certs.avif +++ b/README.d/01-download-certs.avif diff --git a/README.d/02-import-certs.avif b/README.d/02-import-certs.avif Binary files differindex 308be5b..d42994b 100644 --- a/README.d/02-import-certs.avif +++ b/README.d/02-import-certs.avif diff --git a/README.d/03-check-certs.avif b/README.d/03-check-certs.avif Binary files differindex adf1161..33bdc40 100644 --- a/README.d/03-check-certs.avif +++ b/README.d/03-check-certs.avif diff --git a/README.d/05-edit-global-config-overlay.avif b/README.d/05-edit-global-config-overlay.avif Binary files differdeleted file mode 100644 index f2f0f2d..0000000 --- a/README.d/05-edit-global-config-overlay.avif +++ /dev/null diff --git a/README.d/06-run-and-schedule-scripts.avif b/README.d/05-run-and-schedule-scripts.avif Binary files differindex 37e1173..37e1173 100644 --- a/README.d/06-run-and-schedule-scripts.avif +++ b/README.d/05-run-and-schedule-scripts.avif diff --git a/README.d/07-schedule-update.avif b/README.d/06-schedule-update.avif Binary files differindex 7c96f3a..7c96f3a 100644 --- a/README.d/07-schedule-update.avif +++ b/README.d/06-schedule-update.avif diff --git a/README.d/07-edit-global-config-overlay.avif b/README.d/07-edit-global-config-overlay.avif Binary files differnew file mode 100644 index 0000000..f87fda8 --- /dev/null +++ b/README.d/07-edit-global-config-overlay.avif diff --git a/README.d/08-apply-configuration.avif b/README.d/08-apply-configuration.avif Binary files differnew file mode 100644 index 0000000..b66af1a --- /dev/null +++ b/README.d/08-apply-configuration.avif diff --git a/README.d/08-update-scripts.avif b/README.d/09-update-scripts.avif Binary files differindex f549fef..f549fef 100644 --- a/README.d/08-update-scripts.avif +++ b/README.d/09-update-scripts.avif diff --git a/README.d/09-install-scripts.avif b/README.d/10-install-scripts.avif Binary files differindex 00225b1..00225b1 100644 --- a/README.d/09-install-scripts.avif +++ b/README.d/10-install-scripts.avif diff --git a/README.d/10-schedule-script.avif b/README.d/11-schedule-script.avif Binary files differindex 27541b7..27541b7 100644 --- a/README.d/10-schedule-script.avif +++ b/README.d/11-schedule-script.avif diff --git a/README.d/12-install-custom-script.avif b/README.d/12-install-custom-script.avif Binary files differdeleted file mode 100644 index c27408f..0000000 --- a/README.d/12-install-custom-script.avif +++ /dev/null diff --git a/README.d/11-setup-lease-script.avif b/README.d/12-setup-lease-script.avif Binary files differindex 365e0e8..365e0e8 100644 --- a/README.d/11-setup-lease-script.avif +++ b/README.d/12-setup-lease-script.avif diff --git a/README.d/13-install-custom-script.avif b/README.d/13-install-custom-script.avif Binary files differnew file mode 100644 index 0000000..2f01c43 --- /dev/null +++ b/README.d/13-install-custom-script.avif diff --git a/README.d/13-remove-script.avif b/README.d/14-remove-script.avif Binary files differindex a5c7daf..a5c7daf 100644 --- a/README.d/13-remove-script.avif +++ b/README.d/14-remove-script.avif diff --git a/README.d/news-and-changes-notification.svg b/README.d/news-and-changes-notification.svg deleted file mode 100644 index ab8d611..0000000 --- a/README.d/news-and-changes-notification.svg +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="490" height="200" version="1.1" viewBox="0 0 129.65 52.917" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="128.65" height="51.917" rx="1.6081" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.95 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan490" x="180" y="10.85">[MikroTik] 📌 News and configuration changes -</tspan><tspan id="tspan492" x="180" y="25.85"> -</tspan><tspan id="tspan494" x="180" y="40.85">The configuration version on MikroTik increased to 84, -</tspan><tspan id="tspan496" x="180" y="55.85">current configuration may need modification. Please -</tspan><tspan id="tspan498" x="180" y="70.85">review and update global-config-overlay, then re-run -</tspan><tspan id="tspan500" x="180" y="85.85">global-config. -</tspan><tspan id="tspan502" x="180" y="100.85"> -</tspan><tspan id="tspan504" x="180" y="115.85">Changes: -</tspan><tspan id="tspan506" x="180" y="130.85"> ● Introduced new setting to disable news and change -</tspan><tspan id="tspan508" x="180" y="145.85">notifications, dropped version from configuration.</tspan></text> - </g> -</svg> diff --git a/README.d/notification-news-and-changes.avif b/README.d/notification-news-and-changes.avif Binary files differnew file mode 100644 index 0000000..d91b8a0 --- /dev/null +++ b/README.d/notification-news-and-changes.avif diff --git a/README.d/upstream.png b/README.d/upstream.png Binary files differnew file mode 100644 index 0000000..fd5e877 --- /dev/null +++ b/README.d/upstream.png @@ -1,9 +1,12 @@ RouterOS Scripts ================ -[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/network) -[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?style=social)](https://github.com/eworm-de/routeros-scripts/watchers) +[![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.12-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) @@ -18,14 +21,27 @@ 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. +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. 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! +### 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 ------------- @@ -53,7 +69,7 @@ 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/R3.pem" dst-path="letsencrypt-R3.pem"; + /tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/E1.pem" dst-path="letsencrypt-E1.pem"; ![screenshot: download certs](README.d/01-download-certs.avif) @@ -61,21 +77,25 @@ 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 files to your MikroTik device. -* [ISRG Root X1](https://letsencrypt.org/certs/isrgrootx1.pem) -* Let's Encrypt [R3](https://letsencrypt.org/certs/lets-encrypt-r3.pem) +* [ISRG Root X2](https://letsencrypt.org/certs/isrg-root-x2.pem) +* Let's Encrypt [E1](https://letsencrypt.org/certs/lets-encrypt-e1.pem) Then we import the certificates. - /certificate/import file-name=letsencrypt-R3.pem passphrase=""; + /certificate/import file-name=letsencrypt-E1.pem passphrase=""; + +Do not worry that the command is not shown - that happens because it contains +a sensitive property, the passphrase. ![screenshot: import certs](README.d/02-import-certs.avif) -For basic verification we rename the certificates and print their count. Make -sure the certificate count is **two**. +For basic verification we rename the certificates and print them by +fingerprint. Make sure exactly these two certificates ("*E1*" and +"*ISRG-Root-X2*") are shown. - /certificate/set name="R3" [ find where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" ]; - /certificate/set name="ISRG-Root-X1" [ find where fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6" ]; - /certificate/print count-only where fingerprint="67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd" or fingerprint="96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6"; + /certificate/set name="E1" [ find where common-name="E1" ]; + /certificate/set name="ISRG-Root-X2" [ find where common-name="ISRG Root X2" ]; + /certificate/print proplist=name where fingerprint="46494e30379059df18be52124305e606fc59070e5b21076ce113954b60517cda" or fingerprint="69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; ![screenshot: check certs](README.d/03-check-certs.avif) @@ -87,32 +107,56 @@ date and time is set correctly! Now let's download the main scripts and add them in configuration on the fly. - :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script) output=user as-value]->"data"); }; + :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script 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"); }; ![screenshot: import scripts](README.d/04-import-scripts.avif) +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; }"; + +![screenshot: run and schedule scripts](README.d/05-run-and-schedule-scripts.avif) + +### 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 configuration from -[`global-config`](global-config) (the one without `-overlay`). +`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; + /system/script/edit global-config-overlay source; -![screenshot: edit global-config-overlay](README.d/05-edit-global-config-overlay.avif) +![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif) -And finally load configuration and functions and add the scheduler. +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. - /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; }"; +To apply your changes run `global-config`, which will automatically load +the overlay as well: -![screenshot: run and schedule scripts](README.d/06-run-and-schedule-scripts.avif) + /system/script/run global-config; -The last step is optional: Add this scheduler **only** if you want the scripts -to be updated automatically! +![screenshot: apply configuration](README.d/08-apply-configuration.avif) - /system/scheduler/add name="ScriptInstallUpdate" start-time=startup interval=1d on-event=":global ScriptInstallUpdate; \$ScriptInstallUpdate;"; +This last step is required when ever you make changes to your configuration. -![screenshot: schedule update](README.d/07-schedule-update.avif) +> ℹ️ **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=[ $Unix2Dos [ get global-config-overlay source ] ] global-config-overlay;` Updating scripts ---------------- @@ -122,12 +166,12 @@ everything is up-to-date it will not produce any output. $ScriptInstallUpdate; -![screenshot: update scripts](README.d/08-update-scripts.avif) +![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/news-and-changes-notification.svg) +![news and changes notification](README.d/notification-news-and-changes.avif) Adding a script --------------- @@ -137,7 +181,7 @@ a comma separated list of script names. $ScriptInstallUpdate check-certificates,check-routeros-update; -![screenshot: install scripts](README.d/09-install-scripts.avif) +![screenshot: install scripts](README.d/10-install-scripts.avif) Scheduler and events -------------------- @@ -149,7 +193,7 @@ miss an update. /system/scheduler/add name="check-routeros-update" interval=1h on-event="/system/script/run check-routeros-update;"; -![screenshot: schedule script](README.d/10-schedule-script.avif) +![screenshot: schedule script](README.d/11-schedule-script.avif) 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 @@ -159,7 +203,7 @@ cleanup add a scheduler entry. /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/11-setup-lease-script.avif) +![screenshot: setup lease script](README.d/12-setup-lease-script.avif) There's much more to explore... Have fun! @@ -183,9 +227,10 @@ Available scripts * [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 GPS position to server](doc/gps-track.md) -* [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) +* [Use WPA network with hotspot credentials](doc/hotspot-to-wpa.md) * [Create DNS records for IPSec peers](doc/ipsec-to-dns.md) * [Update configuration on IPv6 prefix change](doc/ipv6-update.md) * [Manage IP addresses with bridge status](doc/ip-addr-bridge.md) @@ -200,8 +245,8 @@ Available scripts * [Run scripts on ppp connection](doc/ppp-on-up.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) @@ -215,8 +260,10 @@ Available modules * [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 ----------------------------------- @@ -227,12 +274,9 @@ still use my scripts to manage and deploy yours, by specifying `base-url` This will fetch and install a script `hello-world.rsc` from the given url: - $ScriptInstallUpdate hello-world.rsc "base-url=https://git.eworm.de/cgit/routeros-scripts/plain/README.d/"; + $ScriptInstallUpdate hello-world "base-url=https://git.eworm.de/cgit/routeros-scripts-custom/plain/"; -![screenshot: install custom script](README.d/12-install-custom-script.avif) - -(Yes, the example url still belongs to the repository for easy -handling - but the url can be what ever you use.) +![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 @@ -241,6 +285,26 @@ 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 ----------------- @@ -249,7 +313,7 @@ configuration... /system/script/remove to-be-removed; -![screenshot: remove script](README.d/13-remove-script.avif) +![screenshot: remove script](README.d/14-remove-script.avif) Possibly a scheduler and other configuration has to be removed as well. @@ -258,7 +322,7 @@ Contact We have a Telegram Group [RouterOS-Scripts](https://t.me/routeros_scripts)! -![RouterOS Scripts Telegram Group](README.d/telegram-group.avif) +[![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! @@ -271,7 +335,9 @@ Thanks a lot for [past contributions](CONTRIBUTIONS.md)! ❤️ ### Patches, issues and whishlist Feel free to contact me via e-mail or open an -[issue at github](https://github.com/eworm-de/routeros-scripts/issues). +[issue](https://github.com/eworm-de/routeros-scripts/issues) or +[pull request](https://github.com/eworm-de/routeros-scripts/pulls) +at github. ### Donate @@ -280,7 +346,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://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) +[![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) Thanks a lot for your support! @@ -300,6 +366,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Upstream -------- +![upstream](README.d/upstream.png) + URL: [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts) @@ -308,4 +376,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 deleted file mode 100644 index 848ca52..0000000 --- a/accesslist-duplicates.capsman +++ /dev/null @@ -1,42 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.capsman -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "accesslist-duplicates.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Read; - -:local Seen ({}); -:local Shown ({}); - -:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /caps-man/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /caps-man/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /caps-man/access-list/remove $Remove; - } - } - } - } - :set Seen ($Seen, $Mac); -} diff --git a/accesslist-duplicates.capsman.rsc b/accesslist-duplicates.capsman.rsc new file mode 100644 index 0000000..2ce8302 --- /dev/null +++ b/accesslist-duplicates.capsman.rsc @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.capsman +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ } diff --git a/accesslist-duplicates.local b/accesslist-duplicates.local deleted file mode 100644 index 67f16f3..0000000 --- a/accesslist-duplicates.local +++ /dev/null @@ -1,42 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates.local -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "accesslist-duplicates.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Read; - -:local Seen ({}); -:local Shown ({}); - -:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ - :local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; - :foreach SeenMac in=$Seen do={ - :if ($SeenMac = $Mac) do={ - :local Skip 0; - :foreach ShownMac in=$Shown do={ - :if ($ShownMac = $Mac) do={ :set Skip 1; } - } - :if ($Skip = 0) do={ - /interface/wireless/access-list/print where mac-address=$Mac; - :set Shown ($Shown, $Mac); - - :put "\nNumeric id to remove, any key to skip!"; - :local Remove [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") do={ - :put ("Removing numeric id " . $Remove . "...\n"); - /interface/wireless/access-list/remove $Remove; - } - } - } - } - :set Seen ($Seen, $Mac); -} diff --git a/accesslist-duplicates.local.rsc b/accesslist-duplicates.local.rsc new file mode 100644 index 0000000..51ef6f3 --- /dev/null +++ b/accesslist-duplicates.local.rsc @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.local +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ } diff --git a/accesslist-duplicates.template b/accesslist-duplicates.template deleted file mode 100644 index 8676551..0000000 --- a/accesslist-duplicates.template +++ /dev/null @@ -1,43 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: accesslist-duplicates%TEMPL% -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# print duplicate antries in wireless access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/accesslist-duplicates.md -# -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! - -:local 0 "accesslist-duplicates%TEMPL%"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Read; - -:local Seen ({}); -:local Shown ({}); - -: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 [ :tonum [ $Read ] ]; - :if ([ :typeof $Remove ] = "num") 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 new file mode 100644 index 0000000..770fb30 --- /dev/null +++ b/accesslist-duplicates.template.rsc @@ -0,0 +1,43 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates%TEMPL% +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# print duplicate antries in wireless access list +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +: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={ } diff --git a/accesslist-duplicates.wifi.rsc b/accesslist-duplicates.wifi.rsc new file mode 100644 index 0000000..65f8aaa --- /dev/null +++ b/accesslist-duplicates.wifi.rsc @@ -0,0 +1,34 @@ +#!rsc by RouterOS +# RouterOS script: accesslist-duplicates.wifi +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ } diff --git a/backup-cloud b/backup-cloud deleted file mode 100644 index 38aed1f..0000000 --- a/backup-cloud +++ /dev/null @@ -1,58 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-cloud -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# upload backup to MikroTik cloud -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md - -:local 0 "backup-cloud"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global Identity; - -:global DeviceInfo; -:global LogPrintExit2; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitFullyConnected; - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:do { - # we are not interested in output, but print is - # required to fetch information from cloud - /system/backup/cloud/print as-value; - :if ([ :len [ /system/backup/cloud/find ] ] > 0) do={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword replace=[ get ([ find ]->0) name ]; - } else={ - /system/backup/cloud/upload-file action=create-and-upload \ - password=$BackupPassword; - } - :local Cloud [ /system/backup/cloud/get ([ find ]->0) ]; - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ - message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Name: " . $Cloud->"name" . "\n" . \ - "Size: " . $Cloud->"size" . " B (" . ($Cloud->"size" / 1024) . " KiB)\n" . \ - "Download key: " . $Cloud->"secret-download-key"); silent=true }); -} on-error={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Cloud backup failed"); \ - message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); - $LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; -} diff --git a/backup-cloud.rsc b/backup-cloud.rsc new file mode 100644 index 0000000..cccb41b --- /dev/null +++ b/backup-cloud.rsc @@ -0,0 +1,85 @@ +#!rsc by RouterOS +# RouterOS script: backup-cloud +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script, order=40 +# requires RouterOS, version=7.12 +# +# upload backup to MikroTik cloud +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global BackupRandomDelay; + :global Identity; + :global PackagesUpdateBackupFailure; + + :global DeviceInfo; + :global FormatLine; + :global HumanReadableNum; + :global LogPrint; + :global MkDir; + :global RandomDelay; + :global ScriptFromTerminal; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + :global WaitForFile; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure 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!"); + :error false; + } + + :execute { + :global BackupPassword; + # we are not interested in output, but print is + # required to fetch information from cloud + /system/backup/cloud/print as-value; + :delay 20ms; + :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; + } + /file/add name="tmpfs/backup-cloud/done"; + } as-string; + + :if ([ $WaitForFile "tmpfs/backup-cloud/done" ] = true) do={ + :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 ] . "iB") ] . "\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; + :error false; + } + /file/remove "tmpfs/backup-cloud"; +} on-error={ } diff --git a/backup-email b/backup-email deleted file mode 100644 index 7cdf55e..0000000 --- a/backup-email +++ /dev/null @@ -1,80 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-email -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# create and email backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md - -:local 0 "backup-email"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendEMail2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - -# filename based on identity -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); -:local BackupFile "none"; -:local ConfigFile "none"; -:local Attach ({}); - -# 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 ConfigFile ($FileName . ".rsc"); - :set Attach ($Attach, ($FilePath . ".rsc")); -} - -# send email with status and files -$SendEMail2 ({ origin=$0; \ - subject=([ $SymbolForNotification "floppy-disk,incoming-envelope" ] . \ - "Backup & Config"); \ - message=("See attached files for backup and config export for " . \ - $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile); \ - attach=$Attach; remove-attach=true }); diff --git a/backup-email.rsc b/backup-email.rsc new file mode 100644 index 0000000..64ca69c --- /dev/null +++ b/backup-email.rsc @@ -0,0 +1,124 @@ +#!rsc by RouterOS +# RouterOS script: backup-email +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script, order=20 +# requires RouterOS, version=7.12 +# +# create and email backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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."); + :error false; + } + + :if ($BackupSendBinary != true && \ + $BackupSendExport != true) do={ + $LogPrint error $ScriptName ("Configured to send neither backup nor config export."); + :error false; + } + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure 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!"); + :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; + :error false; + } + :delay 1s; + :set I ($I + 1); + } +} on-error={ } diff --git a/backup-partition b/backup-partition deleted file mode 100644 index a8aecac..0000000 --- a/backup-partition +++ /dev/null @@ -1,36 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-partition -# Copyright (c) 2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# save configuration to fallback partition -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md - -:local 0 "backup-partition"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:if ([ :len [ /partitions/find ] ] < 2) do={ - $LogPrintExit2 error $0 ("Device does not have a fallback partition.") true; -} - -:local ActiveRunning [ /partitions/find where active running ]; - -:if ([ :len $ActiveRunning ] < 1) do={ - $LogPrintExit2 error $0 ("Device is not running from active partition.") true; -} - -:local ActiveRunningVar [ /partitions/get $ActiveRunning ]; - -:do { - /partitions/save-config-to ($ActiveRunningVar->"fallback-to"); - $LogPrintExit2 info $0 ("Saved configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'.") false; -} on-error={ - $LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ - ($ActiveRunningVar->"fallback-to") . "'!") true; -} diff --git a/backup-partition.rsc b/backup-partition.rsc new file mode 100644 index 0000000..503d382 --- /dev/null +++ b/backup-partition.rsc @@ -0,0 +1,57 @@ +#!rsc by RouterOS +# RouterOS script: backup-partition +# Copyright (c) 2022-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script, order=70 +# requires RouterOS, version=7.12 +# +# save configuration to fallback partition +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global PackagesUpdateBackupFailure; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure true; + :error false; + } + + :if ([ :len [ /partitions/find ] ] < 2) do={ + $LogPrint error $ScriptName ("Device does not have a fallback partition."); + :set PackagesUpdateBackupFailure 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; + :error false; + } + + :local FallbackTo [ /partitions/get $ActiveRunning fallback-to ]; + + :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 '" . $FallbackTo . "'."); + } on-error={ + /system/scheduler/remove [ find where name="running-from-backup-partition" ]; + $LogPrint error $ScriptName ("Failed saving configuration to partition '" . $FallbackTo . "'!"); + :set PackagesUpdateBackupFailure true; + :error false; + } +} on-error={ } diff --git a/backup-upload b/backup-upload deleted file mode 100644 index 8ed4149..0000000 --- a/backup-upload +++ /dev/null @@ -1,106 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: backup-upload -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: backup-script -# -# create and upload backup and config file -# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md - -:local 0 "backup-upload"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global BackupPassword; -:global BackupRandomDelay; -:global BackupSendBinary; -:global BackupSendExport; -:global BackupUploadPass; -:global BackupUploadUrl; -:global BackupUploadUser; -:global Domain; -:global Identity; - -:global CharacterReplace; -:global DeviceInfo; -:global IfThenElse; -:global LogPrintExit2; -:global MkDir; -:global RandomDelay; -:global ScriptFromTerminal; -:global SendNotification2; -:global SymbolForNotification; -:global WaitForFile; -:global WaitFullyConnected; - -:if ($BackupSendBinary != true && \ - $BackupSendExport != true) do={ - $LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; -} - -$WaitFullyConnected; - -:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={ - $RandomDelay $BackupRandomDelay; -} - -:if ([ $MkDir $0 ] = false) do={ - $LogPrintExit2 error $0 ("Failed creating directory!") true; -} - -# filename based on identity -:local FileName [ $CharacterReplace ($Identity . "." . $Domain) "." "_" ]; -:local FilePath ($0 . "/" . $FileName); -:local BackupFile "none"; -:local ConfigFile "none"; -:local Failed 0; - -# binary backup -:if ($BackupSendBinary = true) do={ - /system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword; - $WaitForFile ($FilePath . ".backup"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup"); - :set BackupFile ($FileName . ".backup"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading backup file failed!") false; - :set BackupFile "failed"; - :set Failed 1; - } - - /file/remove ($FilePath . ".backup"); -} - -# create configuration export -:if ($BackupSendExport = true) do={ - /export terse show-sensitive file=$FilePath; - $WaitForFile ($FilePath . ".rsc"); - - :do { - /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ - user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); - :set ConfigFile ($FileName . ".rsc"); - } on-error={ - $LogPrintExit2 error $0 ("Uploading configuration export failed!") false; - :set ConfigFile "failed"; - :set Failed 1; - } - - /file/remove ($FilePath . ".rsc"); -} - -$SendNotification2 ({ origin=$0; \ - subject=[ $IfThenElse ($Failed > 0) \ - ([ $SymbolForNotification "warning-sign" ] . "Backup & Config upload with failure") \ - ([ $SymbolForNotification "floppy-disk,up-arrow" ] . "Backup & Config upload") ]; \ - message=("Backup and config export upload for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ] . "\n\n" . \ - "Backup file: " . $BackupFile . "\n" . \ - "Config file: " . $ConfigFile); silent=true }); - -:if ($Failed = 1) do={ - :error "An error occured!"; -} diff --git a/backup-upload.rsc b/backup-upload.rsc new file mode 100644 index 0000000..ef5b7c7 --- /dev/null +++ b/backup-upload.rsc @@ -0,0 +1,161 @@ +#!rsc by RouterOS +# RouterOS script: backup-upload +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: backup-script, order=50 +# requires RouterOS, version=7.12 +# +# create and upload backup and config file +# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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 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."); + :error false; + } + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :set PackagesUpdateBackupFailure 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!"); + :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; + } + + /file/remove ($FilePath . ".backup"); + } + + # create configuration export + :if ($BackupSendExport = true) do={ + /export terse show-sensitive file=$FilePath; + $WaitForFile ($FilePath . ".rsc"); + + :do { + /tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \ + user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc"); + :set ExportFile [ /file/get ($FilePath . ".rsc") ]; + :set ($ExportFile->"name") ($FileName . ".rsc"); + } on-error={ + $LogPrint error $ScriptName ("Uploading configuration export failed!"); + :set ExportFile "failed"; + :set Failed 1; + } + + /file/remove ($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; + } + + /file/remove ($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 ] . "iB") ]) \ + [ $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; + :error false; + } +} on-error={ } diff --git a/capsman-download-packages b/capsman-download-packages deleted file mode 100644 index b745f14..0000000 --- a/capsman-download-packages +++ /dev/null @@ -1,86 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-download-packages -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# download and cleanup packages for CAP installation from CAPsMAN -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md - -:local 0 "capsman-download-packages"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CleanFilePath; -:global DownloadPackage; -:global LogPrintExit2; -:global MkDir; -:global ScriptLock; -:global WaitFullyConnected; - -$ScriptLock $0; -$WaitFullyConnected; - -:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; -:local InstalledVersion [ /system/package/update/get installed-version ]; -:local Updated false; - -:if ([ :len $PackagePath ] = 0) do={ - $LogPrintExit2 warning $0 ("The CAPsMAN package path is not defined, can not download packages.") true; -} - -:if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ - :if ([ $MkDir $PackagePath ] = false) do={ - $LogPrintExit2 warning $0 ("Creating directory at CAPsMAN package path (" . \ - $PackagePath . ") failed!") true; - } - $LogPrintExit2 info $0 ("Created directory at CAPsMAN package path (" . $PackagePath . \ - "). Please place your packages!") false; -} - -:foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ - :local File [ /file/get $Package ]; - :if ($File->"package-architecture" = "mips") do={ - :set ($File->"package-architecture") "mipsbe"; - } - :if ([ $DownloadPackage ($File->"package-name") $InstalledVersion \ - ($File->"package-architecture") $PackagePath ] = true) do={ - :set Updated true; - /file/remove $Package; - } -} - -:if ([ :len [ /system/logging/find where topics~"error" !(topics~"!error") \ - !(topics~"!caps") action=memory !disabled !invalid ] ] < 1) do={ - $LogPrintExit2 warning $0 ("Looks like error messages for 'caps' are not sent to memory. " . \ - "Probably can not download packages automatically.") false; -} else={ - :if ($Updated = false && [ /system/resource/get uptime ] < 2m) do={ - $LogPrintExit2 info $0 ("No packages downloaded, yet. Delaying for logs.") false; - :delay 2m; - } -} - -:foreach Log in=[ /log/find where topics=({"caps"; "error"}) \ - message~("upgrade status: failed, failed to download file '.*-" . $InstalledVersion . \ - "-.*\\.npk', no such file") ] do={ - :local Message [ /log/get $Log message ]; - :local Package [ :pick $Message \ - ([ :find $Message "'" ] + 1) \ - [ :find $Message ("-" . $InstalledVersion . "-") ] ]; - :local Arch [ :pick $Message \ - ([ :find $Message ("-" . $InstalledVersion . "-") ] + 2 + [ :len $InstalledVersion ]) \ - [ :find $Message ".npk" ] ]; - :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ - :set Updated true; - } -} - -:if ($Updated = true) do={ - :if ([ :len [ /system/script/find where name="capsman-rolling-upgrade" ] ] > 0) do={ - /system/script/run capsman-rolling-upgrade; - } else={ - /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; - } -} diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc new file mode 100644 index 0000000..a3bd4a5 --- /dev/null +++ b/capsman-download-packages.capsman.rsc @@ -0,0 +1,83 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages.capsman +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CleanFilePath; + :global DownloadPackage; + :global LogPrint; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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."); + :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!"); + :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; + /file/remove $Package; + } + } + + :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 Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } + } +} on-error={ } diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc new file mode 100644 index 0000000..cad3bcb --- /dev/null +++ b/capsman-download-packages.template.rsc @@ -0,0 +1,94 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages%TEMPL% +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +:do { + :local ScriptName [ :jobname ]; + + :global CleanFilePath; + :global DownloadPackage; + :global LogPrint; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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."); + :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!"); + :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; + /file/remove $Package; + } + } + + :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 Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) 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={ } diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc new file mode 100644 index 0000000..909688f --- /dev/null +++ b/capsman-download-packages.wifi.rsc @@ -0,0 +1,85 @@ +#!rsc by RouterOS +# RouterOS script: capsman-download-packages.wifi +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# download and cleanup packages for CAP installation from CAPsMAN +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-download-packages.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CleanFilePath; + :global DownloadPackage; + :global LogPrint; + :global MkDir; + :global ScriptLock; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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."); + :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!"); + :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; + /file/remove $Package; + } + } + + :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 Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); + :if ([ :len $Script ] > 0) do={ + /system/script/run $Script; + } else={ + /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; + } + } +} on-error={ } diff --git a/capsman-rolling-upgrade b/capsman-rolling-upgrade deleted file mode 100644 index e6b1c51..0000000 --- a/capsman-rolling-upgrade +++ /dev/null @@ -1,36 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: capsman-rolling-upgrade -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# upgrade CAPs one after another -# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md - -:local 0 "capsman-rolling-upgrade"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0; - -:local InstalledVersion [ /system/package/update/get installed-version ]; - -:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ]; -:if ($RemoteCapCount > 0) do={ - :local Delay (600 / $RemoteCapCount); - :if ($Delay > 120) do={ :set Delay 120; } - :foreach RemoteCap in=[ /caps-man/remote-cap/find where version!=$InstalledVersion ] do={ - :local RemoteCapVal [ /caps-man/remote-cap/get $RemoteCap ]; - :if ([ :len $RemoteCapVal ] > 1) do={ - $LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \ - " (" . $RemoteCapVal->"identity" . ")...") false; - /caps-man/remote-cap/upgrade $RemoteCap; - } else={ - $LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false; - } - :delay ($Delay . "s"); - } -} diff --git a/capsman-rolling-upgrade.capsman.rsc b/capsman-rolling-upgrade.capsman.rsc new file mode 100644 index 0000000..11bfd69 --- /dev/null +++ b/capsman-rolling-upgrade.capsman.rsc @@ -0,0 +1,46 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade.capsman +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# requires RouterOS, version=7.12 +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/capsman-rolling-upgrade.template.rsc b/capsman-rolling-upgrade.template.rsc new file mode 100644 index 0000000..e0effd4 --- /dev/null +++ b/capsman-rolling-upgrade.template.rsc @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade%TEMPL% +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# requires RouterOS, version=7.12 +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/capsman-rolling-upgrade.wifi.rsc b/capsman-rolling-upgrade.wifi.rsc new file mode 100644 index 0000000..8ec6f26 --- /dev/null +++ b/capsman-rolling-upgrade.wifi.rsc @@ -0,0 +1,47 @@ +#!rsc by RouterOS +# RouterOS script: capsman-rolling-upgrade.wifi +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: capsman-rolling-upgrade +# requires RouterOS, version=7.12 +# +# upgrade CAPs one after another +# https://git.eworm.de/cgit/routeros-scripts/about/doc/capsman-rolling-upgrade.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/certificate-renew-issued b/certificate-renew-issued deleted file mode 100644 index 29aaa93..0000000 --- a/certificate-renew-issued +++ /dev/null @@ -1,38 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: certificate-renew-issued -# Copyright (c) 2019-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# renew locally issued certificates -# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md - -:local 0 "certificate-renew-issued"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertIssuedExportPass; - -:global LogPrintExit2; -:global MkDir; - -:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ - :local CertVal [ /certificate/get $Cert ]; - /certificate/issued-revoke $Cert; - /certificate/set name=($CertVal->"name" . "-revoked-" . [ /system/clock/get date ]) $Cert; - /certificate/add name=($CertVal->"name") common-name=($CertVal->"common-name") \ - key-usage=($CertVal->"key-usage") subject-alt-name=($CertVal->"subject-alt-name"); - /certificate/sign ($CertVal->"name") ca=($CertVal->"ca"); - :if ([ :typeof ($CertIssuedExportPass->($CertVal->"common-name")) ] = "str") do={ - :if ([ $MkDir "cert-issued" ] = true) do={ - /certificate/export-certificate ($CertVal->"name") type=pkcs12 \ - file-name=("cert-issued/" . $CertVal->"common-name") \ - export-passphrase=($CertIssuedExportPass->($CertVal->"common-name")); - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . \ - "\", exported to \"cert-issued/" . $CertVal->"common-name" . ".p12\".") false; - } else={ - $LogPrintExit2 warning $0 ("Failed creating directory, not exporting certificate.") false; - } - } else={ - $LogPrintExit2 info $0 ("Issued a new certificate for \"" . $CertVal->"common-name" . "\".") false; - } -} diff --git a/certificate-renew-issued.rsc b/certificate-renew-issued.rsc new file mode 100644 index 0000000..45805c5 --- /dev/null +++ b/certificate-renew-issued.rsc @@ -0,0 +1,48 @@ +#!rsc by RouterOS +# RouterOS script: certificate-renew-issued +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# renew locally issued certificates +# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CertIssuedExportPass; + + :global LogPrint; + :global MkDir; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/certs/Cloudflare-Inc-ECC-CA-3.pem b/certs/Cloudflare-Inc-ECC-CA-3.pem new file mode 100644 index 0000000..fa91603 --- /dev/null +++ b/certs/Cloudflare-Inc-ECC-CA-3.pem @@ -0,0 +1,163 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:37:87:64:5e:5f:b4:8c:22:4e:fd:1b:ed:14:0c:3c + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: Jan 27 12:48:08 2020 GMT + Not After : Dec 31 23:59:59 2024 GMT + Subject: C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:b9:ad:4d:66:99:14:0b:46:ec:1f:81:d1:2a:50: + 1e:9d:03:15:2f:34:12:7d:2d:96:b8:88:38:9b:85: + 5f:8f:bf:bb:4d:ef:61:46:c4:c9:73:d4:24:4f:e0: + ee:1c:ce:6c:b3:51:71:2f:6a:ee:4c:05:09:77:d3: + 72:62:a4:9b:d7 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Subject Key Identifier: + A5:CE:37:EA:EB:B0:75:0E:94:67:88:B4:45:FA:D9:24:10:87:96:1F + X509v3 Authority Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + 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 + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl3.digicert.com/Omniroot2025.crl + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.1.1 + CPS: https://www.digicert.com/CPS + Policy: 2.16.840.1.114412.1.2 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 05:24:1d:dd:1b:b0:2a:eb:98:d6:85:e3:39:4d:5e:6b:57:9d: + 82:57:fc:eb:e8:31:a2:57:90:65:05:be:16:44:38:5a:77:02: + b9:cf:10:42:c6:e1:92:a4:e3:45:27:f8:00:47:2c:68:a8:56: + 99:53:54:8f:ad:9e:40:c1:d0:0f:b6:d7:0d:0b:38:48:6c:50: + 2c:49:90:06:5b:64:1d:8b:cc:48:30:2e:de:08:e2:9b:49:22: + c0:92:0c:11:5e:96:92:94:d5:fc:20:dc:56:6c:e5:92:93:bf: + 7a:1c:c0:37:e3:85:49:15:fa:2b:e1:74:39:18:0f:b7:da:f3: + a2:57:58:60:4f:cc:8e:94:00:fc:46:7b:34:31:3e:4d:47:82: + 81:3a:cb:f4:89:5d:0e:ef:4d:0d:6e:9c:1b:82:24:dd:32:25: + 5d:11:78:51:10:3d:a0:35:23:04:2f:65:6f:9c:c1:d1:43:d7: + d0:1e:f3:31:67:59:27:dd:6b:d2:75:09:93:11:24:24:14:cf: + 29:be:e6:23:c3:b8:8f:72:3f:e9:07:c8:24:44:53:7a:b3:b9: + 61:65:a1:4c:0e:c6:48:00:c9:75:63:05:87:70:45:52:83:d3: + 95:9d:45:ea:f0:e8:31:1d:7e:09:1f:0a:fe:3e:dd:aa:3c:5e: + 74:d2:ac:b1 +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa +MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl +clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw +MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD +QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe +nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb +16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME +GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI +KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t +bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF +BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw +CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB +AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un ++ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe +lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H +goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 +CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw +6DEdfgkfCv4+3ao8XnTSrLE= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 33554617 (0x20000b9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Validity + Not Before: May 12 18:46:00 2000 GMT + Not After : May 12 23:59:00 2025 GMT + Subject: C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + Signature Value: + 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: + bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: + 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: + 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: + ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: + 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: + 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: + 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: + 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: + 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: + 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: + 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: + 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: + fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: + ea:63:39:a9 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- diff --git a/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem b/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem new file mode 100644 index 0000000..12084ee --- /dev/null +++ b/certs/DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem @@ -0,0 +1,182 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:f5:bd:06:2b:56:02:f4:7a:b8:50:2c:23:cc:f0:66 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Validity + Not Before: Mar 30 00:00:00 2021 GMT + Not After : Mar 29 23:59:59 2031 GMT + Subject: C=US, O=DigiCert Inc, CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cc:f7:10:62:4f:a6:bb:63:6f:ed:90:52:56:c5: + 6d:27:7b:7a:12:56:8a:f1:f4:f9:d6:e7:e1:8f:bd: + 95:ab:f2:60:41:15:70:db:12:00:fa:27:0a:b5:57: + 38:5b:7d:b2:51:93:71:95:0e:6a:41:94:5b:35:1b: + fa:7b:fa:bb:c5:be:24:30:fe:56:ef:c4:f3:7d:97: + e3:14:f5:14:4d:cb:a7:10:f2:16:ea:ab:22:f0:31: + 22:11:61:69:90:26:ba:78:d9:97:1f:e3:7d:66:ab: + 75:44:95:73:c8:ac:ff:ef:5d:0a:8a:59:43:e1:ac: + b2:3a:0f:f3:48:fc:d7:6b:37:c1:63:dc:de:46:d6: + db:45:fe:7d:23:fd:90:e8:51:07:1e:51:a3:5f:ed: + 49:46:54:7f:2c:88:c5:f4:13:9c:97:15:3c:03:e8: + a1:39:dc:69:0c:32:c1:af:16:57:4c:94:47:42:7c: + a2:c8:9c:7d:e6:d4:4d:54:af:42:99:a8:c1:04:c2: + 77:9c:d6:48:e4:ce:11:e0:2a:80:99:f0:43:70:cf: + 3f:76:6b:d1:4c:49:ab:24:5e:c2:0d:82:fd:46:a8: + ab:6c:93:cc:62:52:42:75:92:f8:9a:fa:5e:5e:b2: + b0:61:e5:1f:1f:b9:7f:09:98:e8:3d:fa:83:7f:47: + 69:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 74:85:80:C0:66:C7:DF:37:DE:CF:BD:29:37:AA:03:1D:BE:ED:CD:17 + X509v3 Authority Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + CA Issuers - URI:http://cacerts.digicert.com/DigiCertGlobalRootG2.crt + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootG2.crl + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.2.1 + Policy: 2.23.140.1.1 + Policy: 2.23.140.1.2.1 + Policy: 2.23.140.1.2.2 + Policy: 2.23.140.1.2.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 90:f1:70:cb:28:97:69:97:7c:74:fd:c0:fa:26:7b:53:ab:ad: + cd:65:fd:ba:9c:06:9c:8a:d7:5a:43:87:ed:4d:4c:56:5f:ad: + c1:c5:b5:05:20:2e:59:d1:ff:4a:f5:a0:2a:d8:b0:95:ad:c9: + 2e:4a:3b:d7:a7:f6:6f:88:29:fc:30:3f:24:84:bb:c3:b7:7b: + 93:07:2c:af:87:6b:76:33:ed:00:55:52:b2:59:9e:e4:b9:d0: + f3:df:e7:0f:fe:dd:f8:c4:b9:10:72:81:09:04:5f:cf:97:9e: + 2e:32:75:8e:cf:9a:58:d2:57:31:7e:37:01:81:b2:66:6d:29: + 1a:b1:66:09:6d:d1:6e:90:f4:b9:fa:2f:01:14:c5:5c:56:64: + 01:d9:7d:87:a8:38:53:9f:8b:5d:46:6d:5c:c6:27:84:81:d4: + 7e:8c:8c:a3:9b:52:e7:c6:88:ec:37:7c:2a:fb:f0:55:5a:38: + 72:10:d8:00:13:cf:4c:73:db:aa:37:35:a8:29:81:69:9c:76: + bc:de:18:7b:90:d4:ca:cf:ef:67:03:fd:04:5a:21:16:b1:ff: + ea:3f:df:dc:82:f5:eb:f4:59:92:23:0d:24:2a:95:25:4c:ca: + a1:91:e6:d4:b7:ac:87:74:b3:f1:6d:a3:99:db:f9:d5:bd:84: + 40:9f:07:98 +-----BEGIN CERTIFICATE----- +MIIEyDCCA7CgAwIBAgIQDPW9BitWAvR6uFAsI8zwZjANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0yMTAzMzAwMDAwMDBaFw0zMTAzMjkyMzU5NTlaMFkxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2Jh +bCBHMiBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMz3EGJPprtjb+2QUlbFbSd7ehJWivH0+dbn4Y+9lavyYEEV +cNsSAPonCrVXOFt9slGTcZUOakGUWzUb+nv6u8W+JDD+Vu/E832X4xT1FE3LpxDy +FuqrIvAxIhFhaZAmunjZlx/jfWardUSVc8is/+9dCopZQ+GssjoP80j812s3wWPc +3kbW20X+fSP9kOhRBx5Ro1/tSUZUfyyIxfQTnJcVPAPooTncaQwywa8WV0yUR0J8 +osicfebUTVSvQpmowQTCd5zWSOTOEeAqgJnwQ3DPP3Zr0UxJqyRewg2C/Uaoq2yT +zGJSQnWS+Jr6Xl6ysGHlHx+5fwmY6D36g39HaaECAwEAAaOCAYIwggF+MBIGA1Ud +EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHSFgMBmx9833s+9KTeqAx2+7c0XMB8G +A1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYIKwYBBQUHAQEEajBoMCQG +CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKG +NGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RH +Mi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDA9BgNVHSAENjA0MAsGCWCGSAGG/WwC +ATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgGBmeBDAECAzANBgkqhkiG +9w0BAQsFAAOCAQEAkPFwyyiXaZd8dP3A+iZ7U6utzWX9upwGnIrXWkOH7U1MVl+t +wcW1BSAuWdH/SvWgKtiwla3JLko716f2b4gp/DA/JIS7w7d7kwcsr4drdjPtAFVS +slme5LnQ89/nD/7d+MS5EHKBCQRfz5eeLjJ1js+aWNJXMX43AYGyZm0pGrFmCW3R +bpD0ufovARTFXFZkAdl9h6g4U5+LXUZtXMYnhIHUfoyMo5tS58aI7Dd8KvvwVVo4 +chDYABPPTHPbqjc1qCmBaZx2vN4Ye5DUys/vZwP9BFohFrH/6j/f3IL16/RZkiMN +JCqVJUzKoZHm1Lesh3Sz8W2jmdv51b2EQJ8HmA== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:3a:f1:e6:a7:11:a9:a0:bb:28:64:b1:1d:09:fa:e5 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75: + ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3: + ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d: + e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54: + 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19: + b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43: + 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4: + 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49: + 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92: + 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95: + 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4: + ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6: + a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82: + 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09: + be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4: + 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34: + 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83: + 29:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 60:67:28:94:6f:0e:48:63:eb:31:dd:ea:67:18:d5:89:7d:3c: + c5:8b:4a:7f:e9:be:db:2b:17:df:b0:5f:73:77:2a:32:13:39: + 81:67:42:84:23:f2:45:67:35:ec:88:bf:f8:8f:b0:61:0c:34: + a4:ae:20:4c:84:c6:db:f8:35:e1:76:d9:df:a6:42:bb:c7:44: + 08:86:7f:36:74:24:5a:da:6c:0d:14:59:35:bd:f2:49:dd:b6: + 1f:c9:b3:0d:47:2a:3d:99:2f:bb:5c:bb:b5:d4:20:e1:99:5f: + 53:46:15:db:68:9b:f0:f3:30:d5:3e:31:e2:8d:84:9e:e3:8a: + da:da:96:3e:35:13:a5:5f:f0:f9:70:50:70:47:41:11:57:19: + 4e:c0:8f:ae:06:c4:95:13:17:2f:1b:25:9f:75:f2:b1:8e:99: + a1:6f:13:b1:41:71:fe:88:2a:c8:4f:10:20:55:d7:f3:14:45: + e5:e0:44:f4:ea:87:95:32:93:0e:fe:53:46:fa:2c:9d:ff:8b: + 22:b9:4b:d9:09:45:a4:de:a4:b8:9a:58:dd:1b:7d:52:9f:8e: + 59:43:88:81:a4:9e:26:d5:6f:ad:dd:0d:c6:37:7d:ed:03:92: + 1b:e5:77:5f:76:ee:3c:8d:c4:5d:56:5b:a2:d9:66:6e:b3:35: + 37:e5:32:b6 +-----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 TLS Hybrid ECC SHA384 2020 CA1.pem b/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem index 446f56f..446f56f 100644 --- a/certs/DigiCert TLS Hybrid ECC SHA384 2020 CA1.pem +++ b/certs/DigiCert-TLS-Hybrid-ECC-SHA384-2020-CA1.pem diff --git a/certs/E1.pem b/certs/E1.pem index 4c3c212..a62fc03 100644 --- a/certs/E1.pem +++ b/certs/E1.pem @@ -122,122 +122,3 @@ 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 1C3.pem b/certs/GTS-CA-1C3.pem index a8432d2..a8432d2 100644 --- a/certs/GTS CA 1C3.pem +++ b/certs/GTS-CA-1C3.pem diff --git a/certs/GTS-CA-1P5.pem b/certs/GTS-CA-1P5.pem new file mode 100644 index 0000000..5be738d --- /dev/null +++ b/certs/GTS-CA-1P5.pem @@ -0,0 +1,238 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:03:bc:50:a3:27:53:f0:91:80:22:ed:f1 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Validity + Not Before: Aug 13 00:00:42 2020 GMT + Not After : Sep 30 00:00:42 2027 GMT + Subject: C=US, O=Google Trust Services LLC, CN=GTS CA 1P5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b3:82:f0:24:8c:bf:2d:87:af:b2:d9:a7:ae:fa: + ca:ba:44:d6:5b:3e:fe:b2:f7:b2:65:16:dc:de:10: + e8:4f:2d:10:58:5a:28:86:87:a1:ee:6a:b3:a0:d9: + 75:4f:7f:a1:52:01:8b:55:a8:4a:5b:06:48:c8:36: + 12:25:ab:89:f9:f2:23:5f:9d:60:65:f9:5c:da:be: + 3a:e8:5c:6d:7d:9c:d0:84:18:85:30:cd:4e:9b:ec: + 3c:d8:b3:e1:96:d4:f3:c5:0b:65:db:8f:b0:74:cb: + f6:1e:f3:78:f1:ac:95:c5:dd:73:c3:31:88:81:af: + 74:aa:6f:fd:0c:e3:05:95:f0:c5:10:4f:65:63:fa: + a0:af:c6:18:3d:c5:a1:df:97:79:d7:05:89:b3:30: + b0:74:ae:3d:92:10:6b:8c:15:77:dd:0b:04:57:fb: + 81:03:dd:ea:22:34:d5:e5:56:b2:f0:c4:8d:41:b1: + c3:02:db:62:ec:80:d0:ff:76:d4:86:e4:04:1a:b6: + b6:0c:2b:62:71:7d:d9:af:d9:f1:5e:fa:c0:1e:ca: + a0:19:5c:55:f0:80:d1:2a:0c:07:86:90:9f:35:e3: + 28:2b:5b:ef:23:c8:a3:1d:a4:a3:3a:ee:fe:83:dc: + 82:4c:25:b0:4d:c5:51:ad:9e:9b:d3:5b:84:c2:1a: + 5a:e9 + 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: + D5:FC:9E:0D:DF:1E:CA:DD:08:97:97:6E:2B:C5:5F:C5:2B:F5:EC:B8 + X509v3 Authority Key Identifier: + E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + Authority Information Access: + OCSP - URI:http://ocsp.pki.goog/gtsr1 + CA Issuers - URI:http://pki.goog/repo/certs/gtsr1.der + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.pki.goog/gtsr1/gtsr1.crl + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.11129.2.5.3 + CPS: https://pki.goog/repository/ + Policy: 2.23.140.1.2.1 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 6c:63:27:ee:23:df:e5:52:68:4d:81:66:91:85:df:7d:65:e5: + 5b:37:31:08:26:b2:07:5d:9a:be:b1:ca:01:b9:ad:bf:9d:77: + f6:51:1d:d7:98:c5:0b:49:a1:7b:a1:d7:d3:68:e5:44:0f:8b: + ba:36:dd:42:82:77:d2:8d:dd:f5:3f:fb:eb:c8:07:98:93:ee: + 5a:d0:b5:3d:de:4b:1c:2d:8c:4d:ec:7e:8c:7b:fe:4e:40:fd: + f0:b4:b3:59:02:10:51:5c:e3:c0:2b:fd:b7:06:48:51:7e:09: + 5e:3f:0f:dc:a7:fe:97:e7:79:c5:0e:44:89:78:c5:69:59:29: + a0:9a:3a:48:36:29:a6:94:93:55:2d:b8:47:b5:e9:96:b5:9f: + 07:cd:a6:ab:3e:32:8a:c0:86:83:c5:c1:41:c8:9f:2f:35:8e: + 0d:c0:07:7a:e1:ac:c9:65:b5:cb:8a:a7:dd:71:d8:61:65:39: + 84:ac:32:3e:f7:7a:36:f1:56:9f:57:a9:41:6d:5a:90:a7:db: + 3a:ea:75:80:0c:63:0b:69:74:6f:07:4c:15:f3:37:28:a5:19: + a4:6e:f5:f6:20:cd:63:b2:7e:c4:2b:09:75:89:da:d1:3c:2e: + 72:4f:36:1a:a1:9e:44:d0:cd:9b:a6:23:08:3f:97:a1:a7:9e: + 5a:a5:f7:09:94:ad:5d:76:5d:28:56:d1:1a:66:51:51:07:7b: + de:3d:b0:c8:ef:30:7a:24:2d:be:b8:b3:86:f6:4b:f7:f0:b5: + 4f:ff:ce:c6:f9:f6:3f:2a:27:08:0f:09:3e:23:5a:c7:e3:42: + 2d:7a:36:e4:3d:98:96:60:39:98:ea:d1:db:63:2a:eb:78:09: + b1:4e:21:b3:8e:b7:ce:3e:92:f1:95:5c:a4:39:d0:c0:2b:c8: + 53:15:f5:d2:2f:82:cd:06:74:67:99:90:77:37:0a:97:2d:c5: + 1c:1e:f4:d0:5b:e9:15:e3:ea:02:09:c8:13:d7:13:70:65:bf: + fb:88:9b:5a:25:be:77:09:e1:a7:6a:4e:11:75:b9:1e:4d:f1: + 00:1b:6a:66:79:8e:c3:6e:d8:6d:a2:22:a2:6d:05:fb:2c:f2: + f1:50:e5:a0:d1:d8:9f:35:7d:fc:70:ab:59:2a:02:f1:be:b0: + d3:f1:f8:cd:12:b9:6a:25:90:5b:e3:85:20:e6:f5:da:cb:40: + 1c:19:34:20:03:61:77:ba:7f:48:0f:49:0b:29:eb:e7:61:64: + c7:63:d1:47:eb:1c:e1:ee:94:46:ef:39:73:cc:ee:4f:2b:8d: + dc:fb:58:a7:b3:65:20:99:95:b9:fb:55:6f:d7:96:6e:94:3d: + f4:7a:92:8e:63:1d:df:6d +-----BEGIN CERTIFICATE----- +MIIFjDCCA3SgAwIBAgINAgO8UKMnU/CRgCLt8TANBgkqhkiG9w0BAQsFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw +MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFQNTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALOC8CSMvy2Hr7LZp676yrpE1ls+/rL3smUW3N4Q6E8tEFha +KIaHoe5qs6DZdU9/oVIBi1WoSlsGSMg2EiWrifnyI1+dYGX5XNq+OuhcbX2c0IQY +hTDNTpvsPNiz4ZbU88ULZduPsHTL9h7zePGslcXdc8MxiIGvdKpv/QzjBZXwxRBP +ZWP6oK/GGD3Fod+XedcFibMwsHSuPZIQa4wVd90LBFf7gQPd6iI01eVWsvDEjUGx +wwLbYuyA0P921IbkBBq2tgwrYnF92a/Z8V76wB7KoBlcVfCA0SoMB4aQnzXjKCtb +7yPIox2kozru/oPcgkwlsE3FUa2em9NbhMIaWukCAwEAAaOCAXYwggFyMA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T +AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU1fyeDd8eyt0Il5duK8VfxSv17LgwHwYD +VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG +CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw +AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt +MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsME0G +A1UdIARGMEQwOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br +aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAgEA +bGMn7iPf5VJoTYFmkYXffWXlWzcxCCayB12avrHKAbmtv5139lEd15jFC0mhe6HX +02jlRA+LujbdQoJ30o3d9T/768gHmJPuWtC1Pd5LHC2MTex+jHv+TkD98LSzWQIQ +UVzjwCv9twZIUX4JXj8P3Kf+l+d5xQ5EiXjFaVkpoJo6SDYpppSTVS24R7XplrWf +B82mqz4yisCGg8XBQcifLzWODcAHeuGsyWW1y4qn3XHYYWU5hKwyPvd6NvFWn1ep +QW1akKfbOup1gAxjC2l0bwdMFfM3KKUZpG719iDNY7J+xCsJdYna0Twuck82GqGe +RNDNm6YjCD+XoaeeWqX3CZStXXZdKFbRGmZRUQd73j2wyO8weiQtvrizhvZL9/C1 +T//Oxvn2PyonCA8JPiNax+NCLXo25D2YlmA5mOrR22Mq63gJsU4hs463zj6S8ZVc +pDnQwCvIUxX10i+CzQZ0Z5mQdzcKly3FHB700FvpFePqAgnIE9cTcGW/+4ibWiW+ +dwnhp2pOEXW5Hk3xABtqZnmOw27YbaIiom0F+yzy8VDloNHYnzV9/HCrWSoC8b6w +0/H4zRK5aiWQW+OFIOb12stAHBk0IANhd7p/SA9JCynr52Fkx2PRR+sc4e6URu85 +c8zuTyuN3PtYp7NlIJmVuftVb9eWbpQ99HqSjmMd320= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:03:e5:93:6f:31:b0:13:49:88:6b:a2:17 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Validity + Not Before: Jun 22 00:00:00 2016 GMT + Not After : Jun 22 00:00:00 2036 GMT + Subject: C=US, O=Google Trust Services LLC, CN=GTS Root R1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b6:11:02:8b:1e:e3:a1:77:9b:3b:dc:bf:94:3e: + b7:95:a7:40:3c:a1:fd:82:f9:7d:32:06:82:71:f6: + f6:8c:7f:fb:e8:db:bc:6a:2e:97:97:a3:8c:4b:f9: + 2b:f6:b1:f9:ce:84:1d:b1:f9:c5:97:de:ef:b9:f2: + a3:e9:bc:12:89:5e:a7:aa:52:ab:f8:23:27:cb:a4: + b1:9c:63:db:d7:99:7e:f0:0a:5e:eb:68:a6:f4:c6: + 5a:47:0d:4d:10:33:e3:4e:b1:13:a3:c8:18:6c:4b: + ec:fc:09:90:df:9d:64:29:25:23:07:a1:b4:d2:3d: + 2e:60:e0:cf:d2:09:87:bb:cd:48:f0:4d:c2:c2:7a: + 88:8a:bb:ba:cf:59:19:d6:af:8f:b0:07:b0:9e:31: + f1:82:c1:c0:df:2e:a6:6d:6c:19:0e:b5:d8:7e:26: + 1a:45:03:3d:b0:79:a4:94:28:ad:0f:7f:26:e5:a8: + 08:fe:96:e8:3c:68:94:53:ee:83:3a:88:2b:15:96: + 09:b2:e0:7a:8c:2e:75:d6:9c:eb:a7:56:64:8f:96: + 4f:68:ae:3d:97:c2:84:8f:c0:bc:40:c0:0b:5c:bd: + f6:87:b3:35:6c:ac:18:50:7f:84:e0:4c:cd:92:d3: + 20:e9:33:bc:52:99:af:32:b5:29:b3:25:2a:b4:48: + f9:72:e1:ca:64:f7:e6:82:10:8d:e8:9d:c2:8a:88: + fa:38:66:8a:fc:63:f9:01:f9:78:fd:7b:5c:77:fa: + 76:87:fa:ec:df:b1:0e:79:95:57:b4:bd:26:ef:d6: + 01:d1:eb:16:0a:bb:8e:0b:b5:c5:c5:8a:55:ab:d3: + ac:ea:91:4b:29:cc:19:a4:32:25:4e:2a:f1:65:44: + d0:02:ce:aa:ce:49:b4:ea:9f:7c:83:b0:40:7b:e7: + 43:ab:a7:6c:a3:8f:7d:89:81:fa:4c:a5:ff:d5:8e: + c3:ce:4b:e0:b5:d8:b3:8e:45:cf:76:c0:ed:40:2b: + fd:53:0f:b0:a7:d5:3b:0d:b1:8a:a2:03:de:31:ad: + cc:77:ea:6f:7b:3e:d6:df:91:22:12:e6:be:fa:d8: + 32:fc:10:63:14:51:72:de:5d:d6:16:93:bd:29:68: + 33:ef:3a:66:ec:07:8a:26:df:13:d7:57:65:78:27: + de:5e:49:14:00:a2:00:7f:9a:a8:21:b6:a9:b1:95: + b0:a5:b9:0d:16:11:da:c7:6c:48:3c:40:e0:7e:0d: + 5a:cd:56:3c:d1:97:05:b9:cb:4b:ed:39:4b:9c:c4: + 3f:d2:55:13:6e:24:b0:d6:71:fa:f4:c1:ba:cc:ed: + 1b:f5:fe:81:41:d8:00:98:3d:3a:c8:ae:7a:98:37: + 18:05:95 + 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: + E4:AF:2B:26:71:1A:2B:48:27:85:2F:52:66:2C:EF:F0:89:13:71:3E + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + 9f:aa:42:26:db:0b:9b:be:ff:1e:96:92:2e:3e:a2:65:4a:6a: + 98:ba:22:cb:7d:c1:3a:d8:82:0a:06:c6:f6:a5:de:c0:4e:87: + 66:79:a1:f9:a6:58:9c:aa:f9:b5:e6:60:e7:e0:e8:b1:1e:42: + 41:33:0b:37:3d:ce:89:70:15:ca:b5:24:a8:cf:6b:b5:d2:40: + 21:98:cf:22:34:cf:3b:c5:22:84:e0:c5:0e:8a:7c:5d:88:e4: + 35:24:ce:9b:3e:1a:54:1e:6e:db:b2:87:a7:fc:f3:fa:81:55: + 14:62:0a:59:a9:22:05:31:3e:82:d6:ee:db:57:34:bc:33:95: + d3:17:1b:e8:27:a2:8b:7b:4e:26:1a:7a:5a:64:b6:d1:ac:37: + f1:fd:a0:f3:38:ec:72:f0:11:75:9d:cb:34:52:8d:e6:76:6b: + 17:c6:df:86:ab:27:8e:49:2b:75:66:81:10:21:a6:ea:3e:f4: + ae:25:ff:7c:15:de:ce:8c:25:3f:ca:62:70:0a:f7:2f:09:66: + 07:c8:3f:1c:fc:f0:db:45:30:df:62:88:c1:b5:0f:9d:c3:9f: + 4a:de:59:59:47:c5:87:22:36:e6:82:a7:ed:0a:b9:e2:07:a0: + 8d:7b:7a:4a:3c:71:d2:e2:03:a1:1f:32:07:dd:1b:e4:42:ce: + 0c:00:45:61:80:b5:0b:20:59:29:78:bd:f9:55:cb:63:c5:3c: + 4c:f4:b6:ff:db:6a:5f:31:6b:99:9e:2c:c1:6b:50:a4:d7:e6: + 18:14:bd:85:3f:67:ab:46:9f:a0:ff:42:a7:3a:7f:5c:cb:5d: + b0:70:1d:2b:34:f5:d4:76:09:0c:eb:78:4c:59:05:f3:33:42: + c3:61:15:10:1b:77:4d:ce:22:8c:d4:85:f2:45:7d:b7:53:ea: + ef:40:5a:94:0a:5c:20:5f:4e:40:5d:62:22:76:df:ff:ce:61: + bd:8c:23:78:d2:37:02:e0:8e:de:d1:11:37:89:f6:bf:ed:49: + 07:62:ae:92:ec:40:1a:af:14:09:d9:d0:4e:b2:a2:f7:be:ee: + ee:d8:ff:dc:1a:2d:de:b8:36:71:e2:fc:79:b7:94:25:d1:48: + 73:5b:a1:35:e7:b3:99:67:75:c1:19:3a:2b:47:4e:d3:42:8e: + fd:31:c8:16:66:da:d2:0c:3c:db:b3:8e:c9:a1:0d:80:0f:7b: + 16:77:14:bf:ff:db:09:94:b2:93:bc:20:58:15:e9:db:71:43: + f3:de:10:c3:00:dc:a8:2a:95:b6:c2:d6:3f:90:6b:76:db:6c: + fe:8c:bc:f2:70:35:0c:dc:99:19:35:dc:d7:c8:46:63:d5:36: + 71:ae:57:fb:b7:82:6d:dc +-----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/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem b/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem new file mode 100644 index 0000000..b514c11 --- /dev/null +++ b/certs/GlobalSign-Atlas-R3-DV-TLS-CA-2022-Q3.pem @@ -0,0 +1,177 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7c:2a:0c:21:3f:c6:55:53:45:c9:1f:19:1f:b8:4e:fa + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Apr 20 12:00:00 2022 GMT + Not After : Apr 20 00:00:00 2025 GMT + Subject: C = BE, O = GlobalSign nv-sa, CN = GlobalSign Atlas R3 DV TLS CA 2022 Q3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b8:a8:7a:66:3c:4e:66:9c:ce:37:a5:54:35:4d: + 36:c7:99:d3:a8:27:36:f2:2f:c6:d5:18:3e:e9:09: + dd:05:d6:d7:2c:34:32:7c:08:63:49:d1:10:37:e5: + 78:5d:11:62:ce:6d:fb:2f:3f:37:94:db:8f:7b:30: + e9:5e:2c:d9:55:3f:b2:db:b9:a0:b5:60:37:8b:a4: + 06:32:35:50:a4:09:af:0a:45:ff:a8:1f:9b:65:8e: + dd:4a:e0:40:a1:e3:63:37:58:90:dd:75:3b:fc:0e: + 1c:82:40:98:bd:70:b1:c1:48:14:14:3c:04:4b:69: + dd:d4:9c:01:a6:e9:21:e3:82:0a:fe:e4:aa:bf:34: + a0:8c:cb:c9:79:6e:3e:5c:6a:52:9e:c4:ed:2b:c5: + 69:fe:50:3c:93:9d:b5:ff:2d:28:a8:6c:06:6c:9d: + c5:af:b2:59:fb:59:77:0d:74:7a:88:84:a4:d4:1d: + d4:ba:20:06:cc:b5:1e:48:4e:74:21:15:86:75:c0: + cc:5a:d1:05:cf:57:16:7a:13:17:ec:c2:4a:ae:d5: + 1e:72:aa:22:5a:8c:9c:82:32:c4:10:e6:42:6e:21: + 86:68:7c:80:23:30:35:d3:bd:b0:5e:0a:29:2b:f0: + 14:b1:18:37:d9:59:25:c3:e7:38:d9:e9:d4:2d:36: + 35:65 + 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: + FA:91:39:63:9A:FB:AD:10:24:E5:BE:B5:B9:DA:AB:D9:C4:46:69:AB + X509v3 Authority Key Identifier: + 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC + Authority Information Access: + OCSP - URI:http://ocsp2.globalsign.com/rootr3 + CA Issuers - URI:http://secure.globalsign.com/cacert/root-r3.crt + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.globalsign.com/root-r3.crl + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.4146.10.1.3 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 14:33:2c:79:e5:3f:82:c6:70:3f:da:59:38:a7:bb:a2:76:ac: + 61:18:05:68:57:d9:0d:fb:8a:46:bc:f1:a8:e8:0c:70:02:1d: + c6:2f:97:ed:36:3e:9e:52:86:2f:5c:62:d8:d5:47:43:9a:73: + d1:2b:25:87:9f:44:b4:14:eb:26:bc:21:47:74:20:bd:9f:a4: + bf:b3:80:1d:4d:35:7d:cd:b9:b5:da:55:f2:90:50:c8:b2:17: + 4e:0e:b4:61:88:29:5f:44:5d:03:7f:57:91:81:d0:eb:30:ae: + d5:2a:ec:82:20:ce:4e:d2:b0:8b:95:02:61:73:d8:69:34:f4: + ad:63:0e:5c:e4:20:1f:a9:7d:ed:8e:e5:1c:04:bb:22:9f:c7: + a9:22:ca:99:3d:02:a7:67:e8:06:2d:fa:04:6b:bb:49:d2:6c: + 99:57:63:6c:2d:c2:61:78:e1:20:b1:fb:f6:bf:e1:82:39:39: + 3c:7b:ef:7d:1a:95:4a:b2:72:da:55:90:ae:ed:dd:e2:70:90: + 7c:1a:ee:b5:32:5a:5d:cf:d6:fa:45:f2:9e:01:0c:31:2f:89: + 84:fe:31:60:0f:fd:ee:a6:5b:84:d5:c7:18:e6:a4:f9:40:30: + 29:18:1e:fe:fc:41:b5:b9:29:05:75:8b:62:1a:5b:22:2e:bf: + e4:59:6c:b0 +-----BEGIN CERTIFICATE----- +MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM +MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv +YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y +NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu +IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy +MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO +N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP +ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c +gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8 +k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW +ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4 +2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW +BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj +move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw +Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1 +cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w +K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD +VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC +AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG +L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60 +YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7 +Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy +2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge +/vxBtbkpBXWLYhpbIi6/5FlssA== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:21:58:53:08:a2 + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Validity + Not Before: Mar 18 10:00:00 2009 GMT + Not After : Mar 18 10:00:00 2029 GMT + Subject: OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cc:25:76:90:79:06:78:22:16:f5:c0:83:b6:84: + ca:28:9e:fd:05:76:11:c5:ad:88:72:fc:46:02:43: + c7:b2:8a:9d:04:5f:24:cb:2e:4b:e1:60:82:46:e1: + 52:ab:0c:81:47:70:6c:dd:64:d1:eb:f5:2c:a3:0f: + 82:3d:0c:2b:ae:97:d7:b6:14:86:10:79:bb:3b:13: + 80:77:8c:08:e1:49:d2:6a:62:2f:1f:5e:fa:96:68: + df:89:27:95:38:9f:06:d7:3e:c9:cb:26:59:0d:73: + de:b0:c8:e9:26:0e:83:15:c6:ef:5b:8b:d2:04:60: + ca:49:a6:28:f6:69:3b:f6:cb:c8:28:91:e5:9d:8a: + 61:57:37:ac:74:14:dc:74:e0:3a:ee:72:2f:2e:9c: + fb:d0:bb:bf:f5:3d:00:e1:06:33:e8:82:2b:ae:53: + a6:3a:16:73:8c:dd:41:0e:20:3a:c0:b4:a7:a1:e9: + b2:4f:90:2e:32:60:e9:57:cb:b9:04:92:68:68:e5: + 38:26:60:75:b2:9f:77:ff:91:14:ef:ae:20:49:fc: + ad:40:15:48:d1:02:31:61:19:5e:b8:97:ef:ad:77: + b7:64:9a:7a:bf:5f:c1:13:ef:9b:62:fb:0d:6c:e0: + 54:69:16:a9:03:da:6e:e9:83:93:71:76:c6:69:85: + 82:17 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 4b:40:db:c0:50:aa:fe:c8:0c:ef:f7:96:54:45:49:bb:96:00: + 09:41:ac:b3:13:86:86:28:07:33:ca:6b:e6:74:b9:ba:00:2d: + ae:a4:0a:d3:f5:f1:f1:0f:8a:bf:73:67:4a:83:c7:44:7b:78: + e0:af:6e:6c:6f:03:29:8e:33:39:45:c3:8e:e4:b9:57:6c:aa: + fc:12:96:ec:53:c6:2d:e4:24:6c:b9:94:63:fb:dc:53:68:67: + 56:3e:83:b8:cf:35:21:c3:c9:68:fe:ce:da:c2:53:aa:cc:90: + 8a:e9:f0:5d:46:8c:95:dd:7a:58:28:1a:2f:1d:de:cd:00:37: + 41:8f:ed:44:6d:d7:53:28:97:7e:f3:67:04:1e:15:d7:8a:96: + b4:d3:de:4c:27:a4:4c:1b:73:73:76:f4:17:99:c2:1f:7a:0e: + e3:2d:08:ad:0a:1c:2c:ff:3c:ab:55:0e:0f:91:7e:36:eb:c3: + 57:49:be:e1:2e:2d:7c:60:8b:c3:41:51:13:23:9d:ce:f7:32: + 6b:94:01:a8:99:e7:2c:33:1f:3a:3b:25:d2:86:40:ce:3b:2c: + 86:78:c9:61:2f:14:ba:ee:db:55:6f:df:84:ee:05:09:4d:bd: + 28:d8:72:ce:d3:62:50:65:1e:eb:92:97:83:31:d9:b3:b5:ca: + 47:58:3f:5f +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- diff --git a/certs/Go Daddy Secure Certificate Authority - G2.pem b/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem index 4faba90..4faba90 100644 --- a/certs/Go Daddy Secure Certificate Authority - G2.pem +++ b/certs/Go-Daddy-Secure-Certificate-Authority-G2.pem diff --git a/certs/Starfield Secure Certificate Authority - G2.pem b/certs/Starfield-Secure-Certificate-Authority-G2.pem index 7772e6b..7772e6b 100644 --- a/certs/Starfield Secure Certificate Authority - G2.pem +++ b/certs/Starfield-Secure-Certificate-Authority-G2.pem diff --git a/check-certificates b/check-certificates deleted file mode 100644 index 99da7d5..0000000 --- a/check-certificates +++ /dev/null @@ -1,127 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-certificates -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# check for certificate validity -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md - -:local 0 "check-certificates"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertRenewPass; -:global CertRenewTime; -:global CertRenewUrl; -:global Identity; - -:global CertificateAvailable -:global CertificateNameByCN; -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -:local FormatExpire do={ - :global CharacterReplace; - :return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ]; -} - -$WaitFullyConnected; - -:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ - :local CertVal [ /certificate/get $Cert ]; - - :do { - :if ([ :len $CertRenewUrl ] = 0) do={ - $LogPrintExit2 info $0 ("No CertRenewUrl given.") true; - } - $LogPrintExit2 info $0 ("Attempting to renew certificate " . ($CertVal->"name") . ".") false; - - :foreach Type in={ ".pem"; ".p12" } do={ - :local CertFileName ([ $UrlEncode ($CertVal->"common-name") ] . $Type); - :do { - /tool/fetch check-certificate=yes-without-crl \ - ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; - $WaitForFile $CertFileName; - :foreach PassPhrase in=$CertRenewPass do={ - /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value; - } - /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={ - $LogPrintExit2 debug $0 ("Could not download certificate file " . $CertFileName) false; - } - } - - :local CertNew [ /certificate/find where common-name=($CertVal->"common-name") fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; - :local CertNewVal [ /certificate/get $CertNew ]; - - :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ - $LogPrintExit2 warning $0 ("The certificate chain is not available!") false; - } - - :if ($Cert != $CertNew) do={ - $LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; - - :if (($CertVal->"private-key") = true && ($CertVal->"private-key") != ($CertNewVal->"private-key")) do={ - /certificate/remove $CertNew; - $LogPrintExit2 warning $0 ("Old certificate '" . ($CertVal->"name") . "' has a private key, new certificate does not. Aborting renew.") true; - } - - /ip/service/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - - /ip/ipsec/identity/set certificate=($CertNewVal->"name") [ find where certificate=($CertVal->"name") ]; - /ip/ipsec/identity/set remote-certificate=($CertNewVal->"name") [ find where remote-certificate=($CertVal->"name") ]; - - /ip/hotspot/profile/set ssl-certificate=($CertNewVal->"name") [ find where ssl-certificate=($CertVal->"name") ]; - - /certificate/remove $Cert; - /certificate/set $CertNew name=($CertVal->"name"); - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed"); \ - message=("A certificate on " . $Identity . " has been renewed.\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertNewVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertNewVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertNewVal->"fingerprint") . "\n" . \ - "Issuer: " . ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertNewVal->"invalid-before") . " to " . ($CertNewVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $FormatExpire ($CertNewVal->"expires-after") ]); silent=true }); - $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " has been renewed.") false; - } on-error={ - $LogPrintExit2 debug $0 ("Could not renew certificate " . ($CertVal->"name") . ".") false; - } -} - -:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) expires-after<2w !(fingerprint=[]) ] do={ - :local CertVal [ /certificate/get $Cert ]; - - :if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Certificate \"" . ($CertVal->"name") . "\" is handled by SCEP, skipping.") false; - } else={ - :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning!"); \ - message=("A certificate on " . $Identity . " " . $State . ".\n\n" . \ - "Name: " . ($CertVal->"name") . "\n" . \ - "CommonName: " . ($CertVal->"common-name") . "\n" . \ - "Private key: " . [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] . "\n" . \ - "Fingerprint: " . ($CertVal->"fingerprint") . "\n" . \ - "Issuer: " . ($CertVal->"ca") . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\n" . \ - "Validity: " . ($CertVal->"invalid-before") . " to " . ($CertVal->"invalid-after") . "\n" . \ - "Expires in: " . [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ]) }); - $LogPrintExit2 info $0 ("The certificate " . ($CertVal->"name") . " " . $State . \ - ", it is invalid after " . ($CertVal->"invalid-after") . ".") false; - } -} diff --git a/check-certificates.rsc b/check-certificates.rsc new file mode 100644 index 0000000..20e2902 --- /dev/null +++ b/check-certificates.rsc @@ -0,0 +1,222 @@ +#!rsc by RouterOS +# RouterOS script: check-certificates +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# check for certificate validity +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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 Name [ :tostr $2 ]; + + :global CertRenewUrl; + :global CertRenewPass; + + :global CertificateNameByCN; + :global EscapeForRegEx; + :global FetchUserAgentStr; + :global LogPrint; + :global UrlEncode; + :global WaitForFile; + + :local Return false; + + :foreach Type in={ ".pem"; ".p12" } do={ + :local CertFileName ([ $UrlEncode $Name ] . $Type); + :do { + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) \ + ($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value; + $WaitForFile $CertFileName; + + :local DecryptionFailed true; + :foreach PassPhrase in=$CertRenewPass do={ + :local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ]; + :if ($Result->"decryption-failures" = 0) do={ + :set DecryptionFailed false; + } + } + /file/remove [ find where name=$CertFileName ]; + + :if ($DecryptionFailed = true) do={ + $LogPrint warning $ScriptName ("Decryption failed for certificate file '" . $CertFileName . "'."); + } + + :foreach CertInChain in=[ /certificate/find where name~("^" . [ $EscapeForRegEx $CertFileName ] . "_[0-9]+\$") \ + common-name!=$Name !(subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $Name ] . "(\\W|\$)")) !(common-name=[]) ] do={ + $CertificateNameByCN [ /certificate/get $CertInChain common-name ]; + } + + :set Return true; + } on-error={ + $LogPrint debug $ScriptName ("Could not download certificate file '" . $CertFileName . "'."); + } + } + + :return $Return; + } + + :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={ + :error false; + } + $WaitFullyConnected; + + :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ + :local CertVal [ /certificate/get $Cert ]; + :local CertNew; + :local LastName; + + :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 ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + :foreach SAN in=($CertVal->"subject-alt-name") do={ + :if ($ImportSuccess = false) do={ + :set LastName [ :pick $SAN ([ :find $SAN ":" ] + 1) [ :len $SAN ] ]; + :set ImportSuccess [ $CheckCertificatesDownloadImport $ScriptName $LastName ]; + } + } + :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."); + + :set CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $LastName ] ] . "\\.(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 CertNewVal; + :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 $CertNew ]) }); + $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={ } diff --git a/check-health b/check-health deleted file mode 100644 index 5da7d2a..0000000 --- a/check-health +++ /dev/null @@ -1,131 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-health -# Copyright (c) 2019-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# check for RouterOS health state -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md - -:local 0 "check-health"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CheckHealthLast; -:global CheckHealthTemperature; -:global CheckHealthTemperatureDeviation; -:global CheckHealthTemperatureNotified; -:global CheckHealthVoltageLow; -:global CheckHealthVoltagePercent; -:global Identity; - -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -:local TempToNum do={ - :global CharacterReplace; - :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; - :return ($T->0 * 10 + $T->1); -} - -:if ([ :len [ /system/health/find ] ] = 0) do={ - $LogPrintExit2 error $0 ("Your device does not provide any health values.") true; -} - -:if ([ :typeof $CheckHealthLast ] != "array") do={ - :set CheckHealthLast ({}); -} -:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ - :set CheckHealthTemperatureNotified ({}); -} - -$ScriptLock $0; - -:foreach Voltage in=[ /system/health/find where type="V" ] do={ - :local Name [ /system/health/get $Voltage name ]; - :local Value [ /system/health/get $Voltage value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :local NumCurr [ $TempToNum $Value ]; - :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; - - :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ - $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ - $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ - "old value: " . ($CheckHealthLast->$Name) . " V\n" . \ - "new value: " . $Value . " V") }); - } else={ - :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); - } - :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ - message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); - } - } - } - :set ($CheckHealthLast->$Name) $Value; -} - -:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ - :local Name [ /system/health/get $PSU name ]; - :local Value [ /system/health/get $PSU value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ($CheckHealthLast->$Name = "ok" && \ - $Value != "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); - } - :if ($CheckHealthLast->$Name != "ok" && \ - $Value = "ok") do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); - } - } - :set ($CheckHealthLast->$Name) $Value; -} - -:foreach Temperature in=[ /system/health/find where type="C" ] do={ - :local Name [ /system/health/get $Temperature name ]; - :local Value [ /system/health/get $Temperature value ]; - - :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ - :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ - $LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; - :set ($CheckHealthTemperature->$Name) 50; - } - :local Validate [ /system/health/get [ find where name=$Name ] value ]; - :while ($Value != $Validate) do={ - :set Value $Validate; - :set Validate [ /system/health/get [ find where name=$Name ] value ]; - } - :if ($Value > $CheckHealthTemperature->$Name && \ - $CheckHealthTemperatureNotified->$Name != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) true; - } - :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ - $CheckHealthTemperatureNotified->$Name = true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ - message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ - $Value . "\C2\B0" . "C") }); - :set ($CheckHealthTemperatureNotified->$Name) false; - } - } - :set ($CheckHealthLast->$Name) $Value; -} diff --git a/check-health.rsc b/check-health.rsc new file mode 100644 index 0000000..2a97ad6 --- /dev/null +++ b/check-health.rsc @@ -0,0 +1,178 @@ +#!rsc by RouterOS +# RouterOS script: check-health +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# check for RouterOS health state +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CheckHealthCPUUtilization; + :global CheckHealthCPUUtilizationNotified; + :global CheckHealthLast; + :global CheckHealthRAMUtilizationNotified; + :global CheckHealthTemperature; + :global CheckHealthTemperatureDeviation; + :global CheckHealthTemperatureNotified; + :global CheckHealthVoltageLow; + :global CheckHealthVoltagePercent; + :global Identity; + + :global FormatLine; + :global HumanReadableNum; + :global IfThenElse; + :global LogPrint; + :global ScriptLock; + :global SendNotification2; + :global SymbolForNotification; + + :local TempToNum do={ + :global CharacterReplace; + :local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; + :return ($T->0 * 10 + $T->1); + } + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 ] . "iB") 8 ] . "\n" . \ + [ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "iB") 8 ] . "\n" . \ + [ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "iB") 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; + } + + :if ([ :len [ /system/health/find ] ] = 0) do={ + $LogPrint debug $ScriptName ("Your device does not provide any health values."); + :error true; + } + + :if ([ :typeof $CheckHealthLast ] != "array") do={ + :set CheckHealthLast ({}); + } + :if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ + :set CheckHealthTemperatureNotified ({}); + } + + + :foreach Voltage in=[ /system/health/find where type="V" ] do={ + :local Name [ /system/health/get $Voltage name ]; + :local Value [ /system/health/get $Voltage value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :local NumCurr [ $TempToNum $Value ]; + :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; + + :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ + $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ + $SendNotification2 ({ origin=$ScriptName; \ + 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=$ScriptName; \ + 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=$ScriptName; \ + subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ + message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); + } + } + } + :set ($CheckHealthLast->$Name) $Value; + } + + :foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ + :local Name [ /system/health/get $PSU name ]; + :local Value [ /system/health/get $PSU value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ($CheckHealthLast->$Name = "ok" && \ + $Value != "ok") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); + } + :if ($CheckHealthLast->$Name != "ok" && \ + $Value = "ok") do={ + $SendNotification2 ({ origin=$ScriptName; \ + subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ + message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); + } + } + :set ($CheckHealthLast->$Name) $Value; + } + + :foreach Temperature in=[ /system/health/find where type="C" ] do={ + :local Name [ /system/health/get $Temperature name ]; + :local Value [ /system/health/get $Temperature value ]; + + :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ + :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ + $LogPrint info $ScriptName ("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=$ScriptName; \ + 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=$ScriptName; \ + 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; + } +} on-error={ } diff --git a/check-lte-firmware-upgrade b/check-lte-firmware-upgrade deleted file mode 100644 index 62943ee..0000000 --- a/check-lte-firmware-upgrade +++ /dev/null @@ -1,82 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-lte-firmware-upgrade -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# check for LTE firmware upgrade, send notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md - -:local 0 "check-lte-firmware-upgrade"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global SentLteFirmwareUpgradeNotification; - -:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={ - :global SentLteFirmwareUpgradeNotification ({}); -} - -:local CheckInterface do={ - :local Interface $1; - - :global Identity; - :global SentLteFirmwareUpgradeNotification; - - :global CharacterReplace; - :global LogPrintExit2; - :global ScriptFromTerminal; - :global SendNotification2; - :global SymbolForNotification; - - :local IntName [ /interface/lte/get $Interface name ]; - :local Firmware; - :local Info; - :do { - :set Firmware [ /interface/lte/firmware-upgrade $Interface once as-value ]; - :set Info [ /interface/lte/monitor $Interface once as-value ]; - } on-error={ - $LogPrintExit2 debug $0 ("Could not get latest LTE firmware version for interface " . \ - $IntName . ".") false; - :return false; - } - - :if (($Firmware->"installed") = ($Firmware->"latest")) do={ - :if ([ $ScriptFromTerminal $0 ] = true) do={ - $LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; - } - :return true; - } - - :if ([ $ScriptFromTerminal $0 ] = true && \ - [ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ - :put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - /system/script/run unattended-lte-firmware-upgrade; - $LogPrintExit2 info $0 ("Scheduled lte firmware upgrade for interface " . $IntName . "...") false; - :return true; - } else={ - :put "Canceled..."; - } - } - - :if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ - $LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ - ($Firmware->"latest") . ".") false; - :return false; - } - - $LogPrintExit2 info $0 ("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . ".") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "LTE firmware upgrade"); \ - message=("A new firmware version " . ($Firmware->"latest") . " is available for " . \ - "LTE interface " . $IntName . " on " . $Identity . ".\n\n" . \ - "Interface: " . [ $CharacterReplace ($Info->"manufacturer" . " " . $Info->"model") ("\"") "" ] . "\n" . \ - "Installed: " . ($Firmware->"installed") . "\n" . \ - "Available: " . ($Firmware->"latest")); silent=true }); - :set ($SentLteFirmwareUpgradeNotification->$IntName) ($Firmware->"latest"); -} - -:foreach Interface in=[ /interface/lte/find ] do={ - $CheckInterface $Interface; -} diff --git a/check-lte-firmware-upgrade.rsc b/check-lte-firmware-upgrade.rsc new file mode 100644 index 0000000..e7f06f3 --- /dev/null +++ b/check-lte-firmware-upgrade.rsc @@ -0,0 +1,103 @@ +#!rsc by RouterOS +# RouterOS script: check-lte-firmware-upgrade +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# check for LTE firmware upgrade, send notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global SentLteFirmwareUpgradeNotification; + + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 once 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={ } diff --git a/check-routeros-update b/check-routeros-update deleted file mode 100644 index 9e1de8e..0000000 --- a/check-routeros-update +++ /dev/null @@ -1,143 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: check-routeros-update -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# check for RouterOS update, send notification and/or install -# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md - -:local 0 "check-routeros-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global SafeUpdateNeighbor; -:global SafeUpdateOnCap; -:global SafeUpdatePatch; -:global SafeUpdateUrl; -:global SentRouterosUpdateNotification; - -:global DeviceInfo; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global VersionToNum; -:global WaitFullyConnected; - -:local DoUpdate do={ - :if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ - /system/script/run packages-update; - } else={ - /system/package/update/install without-paging; - } - :error "Waiting for system to reboot."; -} - -$ScriptLock $0; - -$WaitFullyConnected; - -:if ([ /interface/wireless/cap/get enabled ] = true && \ - [ /caps-man/manager/get enabled ] = false && \ - $SafeUpdateOnCap != true) do={ - $LogPrintExit2 error $0 ("System is managed by CAPsMAN, not checking for RouterOS version.") true; -} - -:if ([ :len [ /system/scheduler/find where name="reboot-for-update" ] ] > 0) do={ - :error "A reboot for update is already scheduled."; -} - -$LogPrintExit2 debug $0 ("Checking for updates...") false; -/system/package/update/check-for-updates without-paging as-value; -:local Update [ /system/package/update/get ]; - -:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ - $LogPrintExit2 info $0 ("System is already up to date.") true; -} - -:local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; -:local NumLatest [ $VersionToNum ($Update->"latest-version") ]; -:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); - -:if ($NumLatest < 117505792) do={ - $LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true; -} - -:if ($NumInstalled < $NumLatest) do={ - :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - - :if ($SafeUpdateNeighbor = true && [ :len [ /ip/neighbor/find where \ - version=($Update->"latest-version" . " (" . $Update->"channel" . ")") ] ] > 0) do={ - $LogPrintExit2 info $0 ("Seen a neighbor running version " . $Update->"latest-version" . ", updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Seen a neighbor running version " . $Update->"latest-version" . " from " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - - :if ([ :len $SafeUpdateUrl ] > 0) do={ - :local Result; - :do { - :set Result [ /tool/fetch check-certificate=yes-without-crl \ - ($SafeUpdateUrl . $Update->"channel" . "?installed=" . $Update->"installed-version" . \ - "&latest=" . $Update->"latest-version") output=user as-value ]; - } on-error={ - $LogPrintExit2 warning $0 ("Failed receiving safe version for " . $Update->"channel" . ".") false; - } - :if ($Result->"status" = "finished" && $Result->"data" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is considered safe, updating...") false; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ - ", updating on " . $Identity . "..."); link=$Link; silent=true }); - $DoUpdate; - } - } - - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $DoUpdate; - } else={ - :put "Canceled..."; - } - } - - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ - $Update->"latest-version" . ".") true; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update"); \ - message=("A new RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ".\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - :set SentRouterosUpdateNotification ($Update->"latest-version"); -} - -:if ($NumInstalled > $NumLatest) do={ - :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \ - $Update->"latest-version" . ".") true; - } - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "warning-sign" ] . "RouterOS version"); \ - message=("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for " . $Identity . ", but it is a downgrade.\n\n" . \ - [ $DeviceInfo ]); link=$Link; silent=true }); - $LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \ - " is available for downgrade.") false; - :set SentRouterosUpdateNotification ($Update->"latest-version"); -} diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc new file mode 100644 index 0000000..c9ab93b --- /dev/null +++ b/check-routeros-update.rsc @@ -0,0 +1,166 @@ +#!rsc by RouterOS +# RouterOS script: check-routeros-update +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# check for RouterOS update, send notification and/or install +# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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 ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + $WaitFullyConnected; + + :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ + :error "A reboot for update is already scheduled."; + } + + $LogPrint debug $ScriptName ("Checking for updates..."); + /system/package/update/check-for-updates without-paging as-value; + :local Update [ /system/package/update/get ]; + + :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={ + $LogPrint info $ScriptName ("System is already up to date."); + :error true; + } + + :local NumInstalled [ $VersionToNum ($Update->"installed-version") ]; + :local NumLatest [ $VersionToNum ($Update->"latest-version") ]; + :local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree"); + + :if ($NumLatest < 117505792) do={ + $LogPrint info $ScriptName ("The version '" . ($Update->"latest-version") . "' is not a valid version."); + :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; + } + + :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) 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; + } + + :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; + } + } + + :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; + } + } + + :if ([ $ScriptFromTerminal $ScriptName ] = 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={ + $LogPrint info $ScriptName ("Already sent the RouterOS update notification for version " . \ + $Update->"latest-version" . "."); + :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" . "."); + :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={ } diff --git a/collect-wireless-mac.capsman b/collect-wireless-mac.capsman deleted file mode 100644 index 9e502e3..0000000 --- a/collect-wireless-mac.capsman +++ /dev/null @@ -1,85 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.capsman -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# provides: lease-script, order=40 -# -# !! Do not edit this file, it is generated from template! - -:local 0 "collect-wireless-mac.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global EitherOr; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0 false 10; - -:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0); - -:foreach Reg in=[ /caps-man/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /caps-man/registration-table/get $Reg ]; - } on-error={ - $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /caps-man/access-list/get $AccessList comment ]) false; - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; - } - } - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /caps-man/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); - } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; - } -} diff --git a/collect-wireless-mac.capsman.rsc b/collect-wireless-mac.capsman.rsc new file mode 100644 index 0000000..dcb303c --- /dev/null +++ b/collect-wireless-mac.capsman.rsc @@ -0,0 +1,96 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.capsman +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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={ } diff --git a/collect-wireless-mac.local b/collect-wireless-mac.local deleted file mode 100644 index a6dbd24..0000000 --- a/collect-wireless-mac.local +++ /dev/null @@ -1,86 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac.local -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# provides: lease-script, order=40 -# -# !! Do not edit this file, it is generated from template! - -:local 0 "collect-wireless-mac.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global EitherOr; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0 false 10; - -:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ]->0); - -:foreach Reg in=[ /interface/wireless/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /interface/wireless/registration-table/get $Reg ]; - } on-error={ - $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /interface/wireless/access-list/get $AccessList comment ]) false; - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; - } - } - :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /interface/wireless/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); - } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; - } -} diff --git a/collect-wireless-mac.local.rsc b/collect-wireless-mac.local.rsc new file mode 100644 index 0000000..7c1122c --- /dev/null +++ b/collect-wireless-mac.local.rsc @@ -0,0 +1,97 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.local +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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={ } diff --git a/collect-wireless-mac.template b/collect-wireless-mac.template deleted file mode 100644 index 42a3d0a..0000000 --- a/collect-wireless-mac.template +++ /dev/null @@ -1,87 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: collect-wireless-mac%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# collect wireless mac adresses in access list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/collect-wireless-mac.md -# -# provides: lease-script, order=40 -# -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! - -:local 0 "collect-wireless-mac%TEMPL%"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global EitherOr; -:global GetMacVendor; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -$ScriptLock $0 false 10; - -:if ([ :len [ /%PATH%/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ - /%PATH%/access-list/add comment="--- collected above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false; -} -:local PlaceBefore ([ /%PATH%/access-list/find where comment="--- collected above ---" disabled ]->0); - -:foreach Reg in=[ /%PATH%/registration-table/find ] do={ - :local RegVal; - :do { - :set RegVal [ /%PATH%/registration-table/get $Reg ]; - } on-error={ - $LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false; - } - - :if ([ :len ($RegVal->"mac-address") ] > 0) do={ - :local AccessList ([ /%PATH%/access-list/find where mac-address=($RegVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - $LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ - [ /%PATH%/access-list/get $AccessList comment ]) false; - } - - :if ([ :len $AccessList ] = 0) do={ - :local Address "no dhcp lease"; - :local DnsName "no dhcp lease"; - :local HostName "no dhcp lease"; - :local Lease ([ /ip/dhcp-server/lease/find where mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); - :if ([ :len $Lease ] > 0) do={ - :set Address [ /ip/dhcp-server/lease/get $Lease address ]; - :set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; - :set DnsName "no dns name"; - :local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); - :if ([ :len $DnsRec ] > 0) do={ - :set DnsName [ /ip/dns/static/get $DnsRec name ]; - } - } - :set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; - :local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); - :local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; - :local Message ("MAC address " . $RegVal->"mac-address" . " (" . $Vendor . ", " . $HostName . ") " . \ - "first seen on " . $DateTime . " connected to SSID " . $RegVal->"ssid" . ", interface " . $RegVal->"interface"); - $LogPrintExit2 info $0 $Message false; - /%PATH%/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes; - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "mobile-phone" ] . $RegVal->"mac-address" . " connected to " . $RegVal->"ssid"); \ - message=("A device with unknown MAC address connected to " . $RegVal->"ssid" . " on " . $Identity . ".\n\n" . \ - "Controller: " . $Identity . "\n" . \ - "Interface: " . $RegVal->"interface" . "\n" . \ - "SSID: " . $RegVal->"ssid" . "\n" . \ - "MAC: " . $RegVal->"mac-address" . "\n" . \ - "Vendor: " . $Vendor . "\n" . \ - "Hostname: " . $HostName . "\n" . \ - "Address: " . $Address . "\n" . \ - "DNS name: " . $DnsName . "\n" . \ - "Date: " . $DateTime) }); - } - } else={ - $LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false; - } -} diff --git a/collect-wireless-mac.template.rsc b/collect-wireless-mac.template.rsc new file mode 100644 index 0000000..b8c5ff8 --- /dev/null +++ b/collect-wireless-mac.template.rsc @@ -0,0 +1,114 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac%TEMPL% +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# requires RouterOS, version=7.12 +# +# 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 to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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={ } diff --git a/collect-wireless-mac.wifi.rsc b/collect-wireless-mac.wifi.rsc new file mode 100644 index 0000000..b8ad939 --- /dev/null +++ b/collect-wireless-mac.wifi.rsc @@ -0,0 +1,96 @@ +#!rsc by RouterOS +# RouterOS script: collect-wireless-mac.wifi +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=40 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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={ } diff --git a/contrib/logo-color.d/browser-01.avif b/contrib/logo-color.d/browser-01.avif Binary files differnew file mode 100644 index 0000000..3dc0a1f --- /dev/null +++ b/contrib/logo-color.d/browser-01.avif diff --git a/contrib/logo-color.d/browser-02.avif b/contrib/logo-color.d/browser-02.avif Binary files differnew file mode 100644 index 0000000..1867fbe --- /dev/null +++ b/contrib/logo-color.d/browser-02.avif diff --git a/contrib/logo-color.d/browser-03.avif b/contrib/logo-color.d/browser-03.avif Binary files differnew file mode 100644 index 0000000..dc24bbb --- /dev/null +++ b/contrib/logo-color.d/browser-03.avif diff --git a/contrib/logo-color.d/script.js b/contrib/logo-color.d/script.js new file mode 100644 index 0000000..82cc204 --- /dev/null +++ b/contrib/logo-color.d/script.js @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..eb2ec6a --- /dev/null +++ b/contrib/logo-color.d/style.css @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..17942ce --- /dev/null +++ b/contrib/logo-color.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="UTF-8"> +<title>RouterOS-Scripts Logo Color Changer</title> +<link rel="stylesheet" type="text/css" href="logo-color.d/style.css"> +<script src="logo-color.d/script.js"></script> +</head> +<body> + +<h1>RouterOS-Scripts Logo Color Changer</h1> + +<p>You want the logo for your own notifications? But you joined the +<a href="https://t.me/routeros_scripts">Telegram Group</a> and want +something that differentiates? Color it!</p> + +<embed class="logo" src="../logo.svg" width="192" height="192" type="image/svg+xml"> + +<p>Select the colors here: +<input id="color1" type="color" value="#222222" onchange="color();"> +<input id="color2" type="color" value="#444444" onchange="color();"> +<input id="color3" type="color" value="#ffffff" onchange="color();"></p> + +<p>Then right-click, click "<i>Take Screenshot</i>" and finally select the +logo and download it.</p> + +<p><img src="logo-color.d/browser-01.avif" width=533 height=482 alt="Screenshot Browser 01"> +<img src="logo-color.d/browser-02.avif" width=533 height=482 alt="Screenshot Browser 02"> +<img src="logo-color.d/browser-03.avif" width=533 height=482 alt="Screenshot Browser 03"></p> + +<p>(This example is with +<a href="https://www.mozilla.org/de/firefox/new/">Firefox</a>. The workflow +for other browsers may differ.)</p> + +<p>See how to +<a href="../../about/doc/mod/notification-telegram.md#set-a-profile-photo">Set +a profile photo</a> for your Telegram bot.</p> + +</body> +</html> diff --git a/contrib/notification.d/script.js b/contrib/notification.d/script.js new file mode 100644 index 0000000..91741fd --- /dev/null +++ b/contrib/notification.d/script.js @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..648ea23 --- /dev/null +++ b/contrib/notification.d/style.css @@ -0,0 +1,36 @@ +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 new file mode 100644 index 0000000..7875036 --- /dev/null +++ b/contrib/notification.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<meta charset="UTF-8"> +<title>RouterOS-Scripts Notification Generator</title> +<link rel="stylesheet" type="text/css" href="notification.d/style.css"> +<script src="notification.d/script.js"></script> +</head> +<body> + +<h1>RouterOS-Scripts Notification Generator</h1> + +<div class="notification"> + <img src="../logo.svg" alt="logo" class="logo" width=48 height=48> + <div class="content"> + <p id="heading" class="heading">[<span id="hostname">MikroTik</span>] <span id="subject">ℹ️ Subject</span></p> + <pre id="message">Message</pre> + <p id="link" class="hint">🔗 <span id="link-text" class="link">https://eworm.de/</span></p> + <p id="queued" class="hint">⏰ This message was queued since <span id="queued-since">oct/18/2022 18:30:48</span> and may be obsolete.</p> + <p id="cut" class="hint">✂️ The message was too long and has been truncated, cut off <span id="cut-percent">13</span>%!</p> + </div> +</div> + +<p>Hostname: <input type="text" value="MikroTik" onchange="update(this, 'hostname')"></p> +<p>Subject: <input type="text" size=50 value="ℹ️ Subject" onchange="update(this, 'subject')"></p> +<p>Message: <textarea id="w3review" name="w3review" rows="4" cols="50" onchange="update(this, 'message')">Message</textarea></p> +<p><input type="checkbox" onclick="visible(this, 'link')"> Show link: <input type="text" value="https://eworm.de/" onchange="update(this, 'link-text')"></p> +<p><input type="checkbox" onclick="visible(this, 'queued')"> Queued since <input type="text" value="oct/18/2022 18:30:48" onchange="update(this, 'queued-since')"></p> +<p><input type="checkbox" onclick="visible(this, 'cut')"> Cut-off with <input type="number" min=1 max=99 value=13 onchange="update(this, 'cut-percent')"> percent</p> + +<p>Then right-click, click "<i>Take Screenshot</i>" and finally select the +notification and download it.</p> + +</body> +</html> diff --git a/daily-psk.capsman b/daily-psk.capsman deleted file mode 100644 index 6e89ff2..0000000 --- a/daily-psk.capsman +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.capsman -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "daily-psk.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DailyPskMatchComment; -:global Identity; - -:global LogPrintExit2; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -$WaitFullyConnected; - -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; - - :local Month [ :pick $Date 0 3 ]; - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; - - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} - -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; - -:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ - :local 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={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /caps-man/access-list/set $AccList private-passphrase=$NewPsk; - - :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - } - } - } -} diff --git a/daily-psk.capsman.rsc b/daily-psk.capsman.rsc new file mode 100644 index 0000000..43651d0 --- /dev/null +++ b/daily-psk.capsman.rsc @@ -0,0 +1,92 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.capsman +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } + } + } + } +} on-error={ } diff --git a/daily-psk.local b/daily-psk.local deleted file mode 100644 index 3876430..0000000 --- a/daily-psk.local +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk.local -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "daily-psk.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DailyPskMatchComment; -:global Identity; - -:global LogPrintExit2; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -$WaitFullyConnected; - -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; - - :local Month [ :pick $Date 0 3 ]; - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; - - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} - -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; - -:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ - :local IntName [ /interface/wireless/access-list/get $AccList interface ]; - :local Ssid [ /interface/wireless/get $IntName ssid ]; - :local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ]; - :local Skip 0; - - :if ($NewPsk != $OldPsk) do={ - $LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; - /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; - - :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - } - } - } -} diff --git a/daily-psk.local.rsc b/daily-psk.local.rsc new file mode 100644 index 0000000..2dbc61b --- /dev/null +++ b/daily-psk.local.rsc @@ -0,0 +1,91 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.local +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } + } + } + } +} on-error={ } diff --git a/daily-psk.template b/daily-psk.template deleted file mode 100644 index af05cd7..0000000 --- a/daily-psk.template +++ /dev/null @@ -1,100 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: daily-psk%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# update daily PSK (pre shared key) -# https://git.eworm.de/cgit/routeros-scripts/about/doc/daily-psk.md -# -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! - -:local 0 "daily-psk%TEMPL%"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DailyPskMatchComment; -:global Identity; - -:global LogPrintExit2; -:global SendNotification2; -:global SymbolForNotification; -:global UrlEncode; -:global WaitForFile; -:global WaitFullyConnected; - -$WaitFullyConnected; - -# return pseudo-random string for PSK -:local GeneratePSK do={ - :local Date [ :tostr $1 ]; - - :global DailyPskSecrets; - - :local Months { "jan"; "feb"; "mar"; "apr"; "may"; "jun"; - "jul"; "aug"; "sep"; "oct"; "nov"; "dec" }; - - :local Month [ :pick $Date 0 3 ]; - :local Day [ :tonum [ :pick $Date 4 6 ] ]; - :local Year [ :pick $Date 7 11 ]; - - :for MIndex from=0 to=[ :len $Months ] do={ - :if ($Months->$MIndex = $Month) do={ - :set Month ($MIndex + 1); - } - } - - :local A ((14 - $Month) / 12); - :local B ($Year - $A); - :local C ($Month + 12 * $A - 2); - :local WeekDay (7000 + $Day + $B + ($B / 4) - ($B / 100) + ($B / 400) + ((31 * $C) / 12)); - :set WeekDay ($WeekDay - (($WeekDay / 7) * 7)); - - :return (($DailyPskSecrets->0->($Day - 1)) . \ - ($DailyPskSecrets->1->($Month - 1)) . \ - ($DailyPskSecrets->2->$WeekDay)); -} - -:local Seen ({}); -:local Date [ /system/clock/get date ]; -:local NewPsk [ $GeneratePSK $Date ]; - -:foreach AccList in=[ /%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={ - $LogPrintExit2 info $0 ("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 ] ] = 1) do={ - :if ([ :len [ /caps-man/interface/find where configuration=$Configuration ] ] > 0) do={ - :foreach SeenSsid in=$Seen do={ - :if ($SeenSsid = $Ssid) do={ - $LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; - :set Skip 1; - } - } - - :if ($Skip = 0) do={ - :set Seen ($Seen, $Ssid); - :local Link ("https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi" . \ - "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ - message=("This is the daily PSK on " . $Identity . ":\n\n" . \ - "SSID: " . $Ssid . "\n" . \ - "PSK: " . $NewPsk . "\n" . \ - "Date: " . $Date . "\n\n" . \ - "A client device specific rule must not exist!"); link=$Link }); - } - } - } -} diff --git a/daily-psk.template.rsc b/daily-psk.template.rsc new file mode 100644 index 0000000..e190ffb --- /dev/null +++ b/daily-psk.template.rsc @@ -0,0 +1,107 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk%TEMPL% +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# update daily PSK (pre shared key) +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +: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={ + :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/actual-configuration/find where configuration.ssid=$Ssid ] ] > 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 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } + } + } + } +} on-error={ } diff --git a/daily-psk.wifi.rsc b/daily-psk.wifi.rsc new file mode 100644 index 0000000..ee3e1b0 --- /dev/null +++ b/daily-psk.wifi.rsc @@ -0,0 +1,92 @@ +#!rsc by RouterOS +# RouterOS script: daily-psk.wifi +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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/actual-configuration/find where configuration.ssid=$Ssid ] ] > 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 ] . "\n" . \ + [ $FormatLine "PSK" $NewPsk ] . "\n" . \ + [ $FormatLine "Date" $Date ] . "\n\n" . \ + "A client device specific rule must not exist!"); link=$Link }); + :set ($Seen->$Ssid) 1; + } + } + } + } +} on-error={ } diff --git a/dhcp-lease-comment.capsman b/dhcp-lease-comment.capsman deleted file mode 100644 index fa34539..0000000 --- a/dhcp-lease-comment.capsman +++ /dev/null @@ -1,30 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.capsman -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=60 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "dhcp-lease-comment.capsman"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /caps-man/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /caps-man/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } -} diff --git a/dhcp-lease-comment.capsman.rsc b/dhcp-lease-comment.capsman.rsc new file mode 100644 index 0000000..4ac228b --- /dev/null +++ b/dhcp-lease-comment.capsman.rsc @@ -0,0 +1,39 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.capsman +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/dhcp-lease-comment.local b/dhcp-lease-comment.local deleted file mode 100644 index 71e6d5e..0000000 --- a/dhcp-lease-comment.local +++ /dev/null @@ -1,30 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment.local -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=60 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! Do not edit this file, it is generated from template! - -:local 0 "dhcp-lease-comment.local"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /interface/wireless/access-list/find where mac-address=($LeaseVal->"mac-address") ]->0); - :if ([ :len $AccessList ] > 0) do={ - :set NewComment [ /interface/wireless/access-list/get $AccessList comment ]; - } - :if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={ - $LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"mac-address" . ": " . $NewComment) false; - /ip/dhcp-server/lease/set comment=$NewComment $Lease; - } -} diff --git a/dhcp-lease-comment.local.rsc b/dhcp-lease-comment.local.rsc new file mode 100644 index 0000000..a49f74f --- /dev/null +++ b/dhcp-lease-comment.local.rsc @@ -0,0 +1,39 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.local +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/dhcp-lease-comment.template b/dhcp-lease-comment.template deleted file mode 100644 index a31812b..0000000 --- a/dhcp-lease-comment.template +++ /dev/null @@ -1,31 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-lease-comment%TEMPL% -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=60 -# -# update dhcp-server lease comment with infos from access-list -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-lease-comment.md -# -# !! This is just a template! Replace '%PATH%' with 'caps-man' -# !! or 'interface wireless'! - -:local 0 "dhcp-lease-comment%TEMPL%"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - :local NewComment; - :local AccessList ([ /%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={ - $LogPrintExit2 info $0 ("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 new file mode 100644 index 0000000..0f0975b --- /dev/null +++ b/dhcp-lease-comment.template.rsc @@ -0,0 +1,44 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment%TEMPL% +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# requires RouterOS, version=7.12 +# +# 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 to generate the real script! +# !! Pattern '%TEMPL%' is replaced, paths are filtered. + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/dhcp-lease-comment.wifi.rsc b/dhcp-lease-comment.wifi.rsc new file mode 100644 index 0000000..c9c091b --- /dev/null +++ b/dhcp-lease-comment.wifi.rsc @@ -0,0 +1,39 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-lease-comment.wifi +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=60 +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/dhcp-to-dns b/dhcp-to-dns deleted file mode 100644 index 368d68f..0000000 --- a/dhcp-to-dns +++ /dev/null @@ -1,97 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: dhcp-to-dns -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=20 -# -# check DHCP leases and add/remove/update DNS entries -# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md - -:local 0 "dhcp-to-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Domain; -:global HostNameInZone; -:global Identity; -:global PrefixInZone; -:global ServerNameInZone; - -:global CharacterReplace; -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0 false 10; - -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "dhcp." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); -:local CommentString ("--- " . $0 . " above ---"); - -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; -} -:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); - -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local MacAddress [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/dhcp-server/lease/find where mac-address=$MacAddress address=($DnsRecordVal->"address") status=bound ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Lease for " . $MacAddress . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; - } else={ - :local Found false; - $LogPrintExit2 info $0 ("Lease expired for " . $MacAddress . " (" . $DnsRecordVal->"name" . "), deleting DNS entry.") false; - /ip/dns/static/remove $DnsRecord; - } -} - -:foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={ - :local LeaseVal; - :do { - :set LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - } on-error={ - $LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false; - } - - :if ([ :len ($LeaseVal->"address") ] > 0) do={ - :local Comment ($CommentPrefix . $LeaseVal->"mac-address"); - :local HostName [ $IfThenElse ([ :len ($LeaseVal->"host-name") ] = 0) \ - [ $CharacterReplace ($LeaseVal->"mac-address") ":" "-" ] \ - [ $CharacterReplace ($LeaseVal->"host-name") " " "" ] ]; - - :local Fqdn ($HostName . "." . [ $IfThenElse ($ServerNameInZone = true) ($LeaseVal->"server" . ".") ] . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - - :local DupMacLeases [ /ip/dhcp-server/lease/find where mac-address=($LeaseVal->"mac-address") status=bound ]; - :if ([ :len $DupMacLeases ] > 1) do={ - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($DupMacLeases->([ :len $DupMacLeases ] - 1)) address ]; - } - - :if ([ :len ($LeaseVal->"host-name") ] > 0) do={ - :local HostNameLeases [ /ip/dhcp-server/lease/find where host-name=($LeaseVal->"host-name") status=bound ]; - :if ([ :len $HostNameLeases ] > 1) do={ - :set ($LeaseVal->"address") [ /ip/dhcp-server/lease/get ($HostNameLeases->0) address ]; - } - } - - :if ($DnsIp = $LeaseVal->"address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; - } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment $DnsRecord; - } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $LeaseVal->"address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($LeaseVal->"address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } - } else={ - $LogPrintExit2 debug $0 ("No address available... Ignoring.") false; - } -} diff --git a/dhcp-to-dns.rsc b/dhcp-to-dns.rsc new file mode 100644 index 0000000..5b6e64a --- /dev/null +++ b/dhcp-to-dns.rsc @@ -0,0 +1,126 @@ +#!rsc by RouterOS +# RouterOS script: dhcp-to-dns +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=20 +# requires RouterOS, version=7.12 +# +# check DHCP leases and add/remove/update DNS entries +# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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 or 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 or 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 or 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={ } diff --git a/doc/accesslist-duplicates.md b/doc/accesslist-duplicates.md index 50720b1..109bebf 100644 --- a/doc/accesslist-duplicates.md +++ b/doc/accesslist-duplicates.md @@ -1,7 +1,14 @@ Find and remove access list duplicates ====================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -15,14 +22,19 @@ entries in wireless access list. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +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. + +For `wifi`: + + $ScriptInstallUpdate accesslist-duplicates.wifi; -For CAPsMAN: +For legacy CAPsMAN: $ScriptInstallUpdate accesslist-duplicates.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate accesslist-duplicates.local; @@ -31,7 +43,7 @@ Usage and invocation Run this script from a terminal: - /system/script/run accesslist-duplicates.local; + /system/script/run accesslist-duplicates.wifi; ![screenshot: example](accesslist-duplicates.d/01-example.avif) @@ -41,5 +53,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 Binary files differnew file mode 100644 index 0000000..e533908 --- /dev/null +++ b/doc/backup-cloud.d/notification.avif diff --git a/doc/backup-cloud.d/notification.svg b/doc/backup-cloud.d/notification.svg deleted file mode 100644 index a0eed63..0000000 --- a/doc/backup-cloud.d/notification.svg +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="403.78" height="273.78" version="1.1" viewBox="0 0 106.83 72.437" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="105.83" height="71.437" rx="1.3229" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.95 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13469" x="180" y="10.85">[MikroTik] 💾☁ Cloud backup -</tspan><tspan id="tspan13471" x="180" y="26.082813"> -</tspan><tspan id="tspan13473" x="180" y="41.082813">Uploaded backup for MikroTik to cloud. -</tspan><tspan id="tspan13475" x="180" y="56.082811"> -</tspan><tspan id="tspan13477" x="180" y="71.082811">Hostname: MikroTik -</tspan><tspan id="tspan13479" x="180" y="86.082811">Board name: CHR -</tspan><tspan id="tspan13481" x="180" y="101.08281">Architecture: x86_64 -</tspan><tspan id="tspan13483" x="180" y="116.08281">RouterOS: -</tspan><tspan id="tspan13485" x="180" y="131.08281"> Channel: stable -</tspan><tspan id="tspan13487" x="180" y="146.08282"> Installed: 7.4.1 -</tspan><tspan id="tspan13489" x="180" y="161.08282">RouterOS-Scripts: -</tspan><tspan id="tspan13491" x="180" y="176.08282"> Version: 83 -</tspan><tspan id="tspan13493" x="180" y="191.08282"> -</tspan><tspan id="tspan13495" x="180" y="206.08282">Name: cloud-20220224-092419 -</tspan><tspan id="tspan13497" x="180" y="221.08282">Size: 370767 B (362 KiB) -</tspan><tspan id="tspan13499" x="180" y="236.08282">Download key: LLDBfPcWXxmSetWilqeJX5V</tspan></text> - </g> -</svg> diff --git a/doc/backup-cloud.md b/doc/backup-cloud.md index 130e3f6..03d5953 100644 --- a/doc/backup-cloud.md +++ b/doc/backup-cloud.md @@ -1,7 +1,14 @@ Upload backup to Mikrotik cloud =============================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -12,14 +19,14 @@ 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 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. +> ⚠️ **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.svg) +![backup-cloud notification](backup-cloud.d/notification.avif) Requirements and installation ----------------------------- @@ -36,9 +43,14 @@ 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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation @@ -60,5 +72,5 @@ See also * [Upload backup to server](backup-upload.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-email.md b/doc/backup-email.md index ab2b9b5..56b0540 100644 --- a/doc/backup-email.md +++ b/doc/backup-email.md @@ -1,7 +1,14 @@ Send backup via e-mail ====================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -29,9 +36,14 @@ 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 -------------------- @@ -52,5 +64,5 @@ See also * [Upload backup to server](backup-upload.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-partition.md b/doc/backup-partition.md index b502330..e2ca8e0 100644 --- a/doc/backup-partition.md +++ b/doc/backup-partition.md @@ -1,7 +1,14 @@ Save configuration to fallback partition ======================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -15,6 +22,14 @@ This script saves the current configuration to fallback 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**: Only the configuration is saved to backup partition. +> Every now and then you should copy your installation over for a recent +> RouterOS version! + Requirements and installation ----------------------------- @@ -39,7 +54,8 @@ 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) +[⬅️ 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 Binary files differnew file mode 100644 index 0000000..83cfb18 --- /dev/null +++ b/doc/backup-upload.d/notification.avif diff --git a/doc/backup-upload.d/notification.svg b/doc/backup-upload.d/notification.svg deleted file mode 100644 index 73b34bd..0000000 --- a/doc/backup-upload.d/notification.svg +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="443.78" height="263.78" version="1.1" viewBox="0 0 117.42 69.792" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="116.42" height="68.792" rx="1.4552" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.95 -6.55)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan10771" x="180" y="10.85">[MikroTik] 💾⬆ Backup & Config upload -</tspan><tspan id="tspan10773" x="180" y="25.85"> -</tspan><tspan id="tspan10775" x="180" y="40.85">Backup and config export upload for MikroTik. -</tspan><tspan id="tspan10777" x="180" y="55.85"> -</tspan><tspan id="tspan10779" x="180" y="70.85">Hostname: MikroTik -</tspan><tspan id="tspan10781" x="180" y="85.85">Board name: CHR -</tspan><tspan id="tspan10783" x="180" y="100.85">Architecture: x86_64 -</tspan><tspan id="tspan10785" x="180" y="115.85">RouterOS: -</tspan><tspan id="tspan10787" x="180" y="130.85"> Channel: stable -</tspan><tspan id="tspan10789" x="180" y="145.85"> Installed: 7.4.1 -</tspan><tspan id="tspan10791" x="180" y="160.85">RouterOS-Scripts: -</tspan><tspan id="tspan10793" x="180" y="175.85"> Version: 83 -</tspan><tspan id="tspan10795" x="180" y="190.85"> -</tspan><tspan id="tspan10797" x="180" y="205.85">Backup file: MikroTik_example_com.backup -</tspan><tspan id="tspan10799" x="180" y="220.85">Config file: MikroTik_example_com.rsc</tspan></text> - </g> -</svg> diff --git a/doc/backup-upload.md b/doc/backup-upload.md index 34df1c6..953ac93 100644 --- a/doc/backup-upload.md +++ b/doc/backup-upload.md @@ -1,7 +1,14 @@ Upload backup to server ======================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -19,7 +26,7 @@ configuration export (`/export terse show-sensitive`) to external server. ### Sample notification -![backup-upload notification](backup-upload.d/notification.svg) +![backup-upload notification](backup-upload.d/notification.avif) Requirements and installation ----------------------------- @@ -35,15 +42,21 @@ 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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). ### Issues with SFTP client @@ -75,5 +88,5 @@ See also * [Save configuration to fallback partition](doc/backup-partition.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-download-packages.md b/doc/capsman-download-packages.md index 0fdd6cb..20fb007 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -1,7 +1,14 @@ Download packages for CAP upgrade from CAPsMAN ============================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -18,24 +25,47 @@ This script automatically downloads these packages. Requirements and installation ----------------------------- -Just install the script on CAPsMAN device: +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. + +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. + +For `wifi`: + + $ScriptInstallUpdate capsman-download-packages.wifi; + +For legacy CAPsMAN: - $ScriptInstallUpdate capsman-download-packages; + $ScriptInstallUpdate capsman-download-packages.capsman; -Optionally add a scheduler to run after startup: +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;" start-time=startup; + /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. The script tries to download missing packages by guessing -from system log. +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. Usage and invocation -------------------- Run the script manually: - /system/script/run capsman-download-packages; + /system/script/run capsman-download-packages.wifi; ... or from scheduler. @@ -49,5 +79,5 @@ See also * [Run rolling CAP upgrades from CAPsMAN](capsman-rolling-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/capsman-rolling-upgrade.md b/doc/capsman-rolling-upgrade.md index 94a2a79..8362794 100644 --- a/doc/capsman-rolling-upgrade.md +++ b/doc/capsman-rolling-upgrade.md @@ -1,7 +1,14 @@ Run rolling CAP upgrades from CAPsMAN ===================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -20,9 +27,17 @@ parallel. Requirements and installation ----------------------------- -Just install the script: +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. + +For `wifi`: + + $ScriptInstallUpdate capsman-rolling-upgrade.wifi; + +For legacy CAPsMAN: - $ScriptInstallUpdate capsman-rolling-upgrade; + $ScriptInstallUpdate capsman-rolling-upgrade.capsman; Usage and invocation -------------------- @@ -33,7 +48,7 @@ that script when required. Alternatively run it manually: - /system/script/run capsman-rolling-upgrade; + /system/script/run capsman-rolling-upgrade.wifi; See also -------- @@ -41,5 +56,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 d8201a7..2df8be3 100644 --- a/doc/certificate-renew-issued.md +++ b/doc/certificate-renew-issued.md @@ -1,7 +1,14 @@ Renew locally issued certificates ================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -28,6 +35,10 @@ 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 -------------------- @@ -46,5 +57,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 Binary files differnew file mode 100644 index 0000000..7c250da --- /dev/null +++ b/doc/check-certificates.d/notification.avif diff --git a/doc/check-certificates.d/notification.svg b/doc/check-certificates.d/notification.svg deleted file mode 100644 index e1d8baa..0000000 --- a/doc/check-certificates.d/notification.svg +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="683.78" height="203.78" version="1.1" viewBox="0 0 180.92 53.917" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="179.92" height="52.917" rx="2.249" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.014 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2179" x="180" y="10.85">[MikroTik] 🔏 Certificate renewed -</tspan><tspan id="tspan2181" x="180" y="25.85"> -</tspan><tspan id="tspan2183" x="180" y="40.85">A certificate on MikroTik has been renewed. -</tspan><tspan id="tspan2185" x="180" y="55.85"> -</tspan><tspan id="tspan2187" x="180" y="70.85">Name: example.com -</tspan><tspan id="tspan2189" x="180" y="85.85">CommonName: example.com -</tspan><tspan id="tspan2191" x="180" y="100.85">Private key: available -</tspan><tspan id="tspan2193" x="180" y="115.85">Fingerprint: cc54cdd01fcd7698ecb71213874be776906eb33d26cd57754d168632f14c4c8b -</tspan><tspan id="tspan2195" x="180" y="130.85">Issuer: R3 -</tspan><tspan id="tspan2197" x="180" y="145.85">Validity: may/22/2021 22:29:34 to aug/20/2021 22:29:34 -</tspan><tspan id="tspan2199" x="180" y="160.85">Expires in: 11w 5d 08:18:06</tspan></text> - </g> -</svg> diff --git a/doc/check-certificates.md b/doc/check-certificates.md index 5198e52..62b9ceb 100644 --- a/doc/check-certificates.md +++ b/doc/check-certificates.md @@ -1,7 +1,14 @@ Renew certificates and notify on expiration =========================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -14,7 +21,7 @@ certificates that are still about to expire. ### Sample notification -![check-certificates notification](check-certificates.d/notification.svg) +![check-certificates notification](check-certificates.d/notification.avif) Requirements and installation ----------------------------- @@ -30,14 +37,22 @@ 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 `CN.pem` (`PEM` format) or -`CN.p12` (`PKCS#12` format). +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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation @@ -51,9 +66,26 @@ Just run the script: /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: - /system/scheduler/add name=check-certificates-startup on-event="/system/script/run check-certificates;" start-time=startup; +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; See also -------- @@ -61,5 +93,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 Binary files differnew file mode 100644 index 0000000..326e7fe --- /dev/null +++ b/doc/check-health.d/notification-01-cpu-utilization-high.avif diff --git a/doc/check-health.d/notification-01-voltage.svg b/doc/check-health.d/notification-01-voltage.svg deleted file mode 100644 index 4c9caad..0000000 --- a/doc/check-health.d/notification-01-voltage.svg +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="443.78" height="123.78" version="1.1" viewBox="0 0 117.42 32.75" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="116.42" height="31.75" rx="1.4552" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.077 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13643" x="180" y="10.85">[MikroTik] ⚡📉 Health warning: voltage -</tspan><tspan id="tspan13645" x="180" y="25.85"> -</tspan><tspan id="tspan13647" x="180" y="40.85">The voltage on MikroTik jumped more than 10%. -</tspan><tspan id="tspan13649" x="180" y="55.85"> -</tspan><tspan id="tspan13651" x="180" y="70.85">old value: 16.2V -</tspan><tspan id="tspan13653" x="180" y="85.85">new value: 12.4V</tspan></text> - </g> -</svg> diff --git a/doc/check-health.d/notification-02-cpu-utilization-ok.avif b/doc/check-health.d/notification-02-cpu-utilization-ok.avif Binary files differnew file mode 100644 index 0000000..811ccd7 --- /dev/null +++ b/doc/check-health.d/notification-02-cpu-utilization-ok.avif diff --git a/doc/check-health.d/notification-02-temperature-high.svg b/doc/check-health.d/notification-02-temperature-high.svg deleted file mode 100644 index 0ab9488..0000000 --- a/doc/check-health.d/notification-02-temperature-high.svg +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="503.78" height="83.78" version="1.1" viewBox="0 0 133.29 22.167" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="132.29" height="21.167" rx="1.6536" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.077 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13709" x="180" y="10.85">[MikroTik] 🔥 Health warning: temperature -</tspan><tspan id="tspan13711" x="180" y="25.85"> -</tspan><tspan id="tspan13713" x="180" y="40.85">The temperature on MikroTik is above threshold: 51°C</tspan></text> - </g> -</svg> diff --git a/doc/check-health.d/notification-03-ram-utilization-high.avif b/doc/check-health.d/notification-03-ram-utilization-high.avif Binary files differnew file mode 100644 index 0000000..59155c5 --- /dev/null +++ b/doc/check-health.d/notification-03-ram-utilization-high.avif diff --git a/doc/check-health.d/notification-03-temperature-ok.svg b/doc/check-health.d/notification-03-temperature-ok.svg deleted file mode 100644 index 180d13f..0000000 --- a/doc/check-health.d/notification-03-temperature-ok.svg +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="533.78" height="83.78" version="1.1" viewBox="0 0 141.23 22.167" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="140.23" height="21.167" rx="1.7529" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.077 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13679" x="180" y="10.85">[MikroTik] ✅ Health recovery: temperature -</tspan><tspan id="tspan13681" x="180" y="25.85"> -</tspan><tspan id="tspan13683" x="180" y="40.85">The temperature on MikroTik dropped below threshold: 48°C</tspan></text> - </g> -</svg> diff --git a/doc/check-health.d/notification-04-psu-fail.svg b/doc/check-health.d/notification-04-psu-fail.svg deleted file mode 100644 index f7efe4b..0000000 --- a/doc/check-health.d/notification-04-psu-fail.svg +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="513.78" height="83.78" version="1.1" viewBox="0 0 135.94 22.167" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="134.94" height="21.167" rx="1.6867" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.077 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2171" x="180" y="10.85">[MikroTik] ❌ Health warning: psu1-state -</tspan><tspan id="tspan2173" x="180" y="25.85"> -</tspan><tspan id="tspan2175" x="180" y="40.85">The power supply unit 'psu1-state' on MikroTik failed!</tspan></text> - </g> -</svg> diff --git a/doc/check-health.d/notification-04-ram-utilization-ok.avif b/doc/check-health.d/notification-04-ram-utilization-ok.avif Binary files differnew file mode 100644 index 0000000..d995b9a --- /dev/null +++ b/doc/check-health.d/notification-04-ram-utilization-ok.avif diff --git a/doc/check-health.d/notification-05-psu-ok.svg b/doc/check-health.d/notification-05-psu-ok.svg deleted file mode 100644 index 0a3f05c..0000000 --- a/doc/check-health.d/notification-05-psu-ok.svg +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="533.78" height="83.78" version="1.1" viewBox="0 0 141.23 22.167" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="140.23" height="21.167" rx="1.7529" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.077 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13739" x="180" y="10.85">[MikroTik] ✅ Health recovery: psu1-state -</tspan><tspan id="tspan13741" x="180" y="25.85"> -</tspan><tspan id="tspan13743" x="180" y="40.85">The power supply unit 'psu1-state' on MikroTik recovered!</tspan></text> - </g> -</svg> diff --git a/doc/check-health.d/notification-05-voltage.avif b/doc/check-health.d/notification-05-voltage.avif Binary files differnew file mode 100644 index 0000000..17a385b --- /dev/null +++ b/doc/check-health.d/notification-05-voltage.avif diff --git a/doc/check-health.d/notification-06-temperature-high.avif b/doc/check-health.d/notification-06-temperature-high.avif Binary files differnew file mode 100644 index 0000000..60d3802 --- /dev/null +++ b/doc/check-health.d/notification-06-temperature-high.avif diff --git a/doc/check-health.d/notification-07-temperature-ok.avif b/doc/check-health.d/notification-07-temperature-ok.avif Binary files differnew file mode 100644 index 0000000..4afed02 --- /dev/null +++ b/doc/check-health.d/notification-07-temperature-ok.avif diff --git a/doc/check-health.d/notification-08-psu-fail.avif b/doc/check-health.d/notification-08-psu-fail.avif Binary files differnew file mode 100644 index 0000000..ad049ac --- /dev/null +++ b/doc/check-health.d/notification-08-psu-fail.avif diff --git a/doc/check-health.d/notification-09-psu-ok.avif b/doc/check-health.d/notification-09-psu-ok.avif Binary files differnew file mode 100644 index 0000000..26f5a74 --- /dev/null +++ b/doc/check-health.d/notification-09-psu-ok.avif diff --git a/doc/check-health.md b/doc/check-health.md index 9ee16bb..ee52b61 100644 --- a/doc/check-health.md +++ b/doc/check-health.md @@ -1,7 +1,14 @@ Notify about health state ========================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -12,32 +19,46 @@ Description This script is run from scheduler periodically, sending notification on health related events: -* voltage jumps up or down more than configured threshold or drops below limit +* high CPU utilization +* high RAM utilization (low available RAM) +* voltage jumps up or down more than configured threshold +* voltage drops below hard lower limit * power supply failed or recovered * temperature is above or below threshold Note that bad initial state will not trigger an event. -Only sensors available in hardware can be checked. See what your -hardware supports: +Monitoring CPU and RAM utilization (available processing and memory +resources) works on all devices. Other than that only sensors available +in hardware can be checked. See what your hardware supports: /system/health/print; ### Sample notifications +#### 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-01-voltage.svg) +![check-health notification voltage](check-health.d/notification-05-voltage.avif) #### Temperature -![check-health notification](check-health.d/notification-02-temperature-high.svg) -![check-health notification](check-health.d/notification-03-temperature-ok.svg) +![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](check-health.d/notification-04-psu-fail.svg) -![check-health notification](check-health.d/notification-05-psu-ok.svg) +![check-health notification psu fail](check-health.d/notification-08-psu-fail.avif) +![check-health notification psu ok](check-health.d/notification-09-psu-ok.avif) Requirements and installation ----------------------------- @@ -45,7 +66,11 @@ Requirements and installation Just install the script and create a scheduler: $ScriptInstallUpdate check-health; - /system/scheduler/add interval=1m name=check-health on-event="/system/script/run check-health;" start-time=startup; + /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. Configuration ------------- @@ -56,11 +81,16 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.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-lte-firmware-upgrade.d/notification.avif b/doc/check-lte-firmware-upgrade.d/notification.avif Binary files differnew file mode 100644 index 0000000..c440da5 --- /dev/null +++ b/doc/check-lte-firmware-upgrade.d/notification.avif diff --git a/doc/check-lte-firmware-upgrade.d/notification.svg b/doc/check-lte-firmware-upgrade.d/notification.svg deleted file mode 100644 index 5992462..0000000 --- a/doc/check-lte-firmware-upgrade.d/notification.svg +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="483.78" height="153.78" version="1.1" viewBox="0 0 128 40.687" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="127" height="39.687" rx="1.5875" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.014 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13600" x="180" y="10.85">[MikroTik] ✨ LTE firmware upgrade -</tspan><tspan id="tspan13602" x="180" y="25.85"> -</tspan><tspan id="tspan13604" x="180" y="40.85">A new firmware version R11e-LTE6_V033 is available -</tspan><tspan id="tspan13606" x="180" y="55.85">for LTE interface lte on MikroTik. -</tspan><tspan id="tspan13608" x="180" y="70.85"> -</tspan><tspan id="tspan13610" x="180" y="85.85">Interface: MikroTik R11e-LTE6 -</tspan><tspan id="tspan13612" x="180" y="100.85">Installed: R11e-LTE6_V027 -</tspan><tspan id="tspan13614" x="180" y="115.85">Available: R11e-LTE6_V033</tspan></text> - </g> -</svg> diff --git a/doc/check-lte-firmware-upgrade.md b/doc/check-lte-firmware-upgrade.md index f3b3bfc..bec3177 100644 --- a/doc/check-lte-firmware-upgrade.md +++ b/doc/check-lte-firmware-upgrade.md @@ -1,7 +1,14 @@ Notify on LTE firmware upgrade ============================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -19,7 +26,7 @@ upgrades. Currently supported LTE hardware: ### Sample notification -![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.svg) +![check-lte-firmware-upgrade notification](check-lte-firmware-upgrade.d/notification.avif) Requirements and installation ----------------------------- @@ -47,5 +54,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 Binary files differnew file mode 100644 index 0000000..50317cf --- /dev/null +++ b/doc/check-routeros-update.d/notification.avif diff --git a/doc/check-routeros-update.d/notification.svg b/doc/check-routeros-update.d/notification.svg deleted file mode 100644 index d4dbc43..0000000 --- a/doc/check-routeros-update.d/notification.svg +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="523.78" height="253.78" version="1.1" viewBox="0 0 138.58 67.146" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="137.58" height="66.146" rx="1.7198" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.95 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13541" x="180" y="10.85">[MikroTik] ✨ RouterOS update -</tspan><tspan id="tspan13543" x="180" y="25.85"> -</tspan><tspan id="tspan13545" x="180" y="40.85">A new RouterOS version 7.4.1 is available for MikroTik. -</tspan><tspan id="tspan13547" x="180" y="55.85"> -</tspan><tspan id="tspan13549" x="180" y="70.85">Hostname: MikroTik -</tspan><tspan id="tspan13551" x="180" y="85.85">Board name: CHR -</tspan><tspan id="tspan13553" x="180" y="100.85">Architecture: x86_64 -</tspan><tspan id="tspan13555" x="180" y="115.85">RouterOS: -</tspan><tspan id="tspan13557" x="180" y="130.85"> Channel: stable -</tspan><tspan id="tspan13559" x="180" y="145.85"> Installed: 7.3.1 -</tspan><tspan id="tspan13561" x="180" y="160.85"> Available: 7.4.1 -</tspan><tspan id="tspan13563" x="180" y="175.85">RouterOS-Scripts: -</tspan><tspan id="tspan13565" x="180" y="190.85"> Version: 83</tspan></text> - <text id="text6580" transform="translate(-59.247 -209.41)" fill="#000000" font-family="sans-serif" font-size="3.175px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:3.96875px;shape-inside:url(#rect6582);white-space:pre" xml:space="preserve"><tspan id="tspan13567" x="61.890625" y="254.76135"> -</tspan><tspan id="tspan13569" x="61.890625" y="258.7301">🔗 https://mikrotik.com/download/changelogs/stable-release-tree</tspan></text> - </g> -</svg> diff --git a/doc/check-routeros-update.md b/doc/check-routeros-update.md index edffcbb..dbb2b89 100644 --- a/doc/check-routeros-update.md +++ b/doc/check-routeros-update.md @@ -1,7 +1,14 @@ Notify on RouterOS update ========================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -30,7 +37,7 @@ automatically is supported. ### Sample notification -![check-routeros-update notification](check-routeros-update.d/notification.svg) +![check-routeros-update notification](check-routeros-update.d/notification.avif) Requirements and installation ----------------------------- @@ -46,19 +53,28 @@ And add a scheduler for automatic update notification: Configuration ------------- -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: +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: + +* `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 -* `SafeUpdateNeighbor`: install updates automatically if seen in neighbor list -* `SafeUpdateOnCap`: check for updates even if device is managed by CAPsMAN -* `SafeUpdatePatch`: install patch updates automatically -* `SafeUpdateUrl`: url to check for safe update, the channel (`long-term`, -`stable` or `testing`) is appended +> ℹ️ **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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation @@ -72,6 +88,14 @@ 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 -------- @@ -79,5 +103,5 @@ See also * [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/collect-wireless-mac.d/notification.avif b/doc/collect-wireless-mac.d/notification.avif Binary files differnew file mode 100644 index 0000000..a2833f0 --- /dev/null +++ b/doc/collect-wireless-mac.d/notification.avif diff --git a/doc/collect-wireless-mac.d/notification.svg b/doc/collect-wireless-mac.d/notification.svg deleted file mode 100644 index aae8cc5..0000000 --- a/doc/collect-wireless-mac.d/notification.svg +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="493.78" height="243.78" version="1.1" viewBox="0 0 130.65 64.5" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="129.65" height="63.5" rx="1.6206" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.014 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13404" x="180" y="10.85">[MikroTik] 📱 48:F1:7F:D0:E5:4E connected to Wifi -</tspan><tspan id="tspan13406" x="180" y="25.85"> -</tspan><tspan id="tspan13408" x="180" y="40.85">A device with unknown MAC address connected to Wifi -</tspan><tspan id="tspan13410" x="180" y="55.85">on MikroTik. -</tspan><tspan id="tspan13412" x="180" y="70.85"> -</tspan><tspan id="tspan13414" x="180" y="85.85">Controller: MikroTik -</tspan><tspan id="tspan13416" x="180" y="100.85">Interface: wl5-wifi -</tspan><tspan id="tspan13418" x="180" y="115.85">SSID: Wifi -</tspan><tspan id="tspan13420" x="180" y="130.85">MAC: 48:F1:7F:D0:E5:4E -</tspan><tspan id="tspan13422" x="180" y="145.85">Vendor: Intel Corporate -</tspan><tspan id="tspan13424" x="180" y="160.85">Hostname: host-523c8e0e -</tspan><tspan id="tspan13426" x="180" y="175.85">Address: 192.168.20.254 -</tspan><tspan id="tspan13428" x="180" y="190.85">DNS name: host-523c8e0e.dhcp.MikroTik.example.com -</tspan><tspan id="tspan13430" x="180" y="205.85">Date: jun/15/2021 09:21:56</tspan></text> - </g> -</svg> diff --git a/doc/collect-wireless-mac.md b/doc/collect-wireless-mac.md index e6ef990..b0a2298 100644 --- a/doc/collect-wireless-mac.md +++ b/doc/collect-wireless-mac.md @@ -1,7 +1,14 @@ Collect MAC addresses in wireless access list ============================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -17,19 +24,24 @@ and modify it to your needs. ### Sample notification -![collect-wireless-mac notification](collect-wireless-mac.d/notification.svg) +![collect-wireless-mac notification](collect-wireless-mac.d/notification.avif) Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +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. + +For `wifi`: + + $ScriptInstallUpdate collect-wireless-mac.wifi; -For CAPsMAN: +For legacy CAPsMAN: $ScriptInstallUpdate collect-wireless-mac.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate collect-wireless-mac.local; @@ -42,7 +54,8 @@ entries are to be added. Also notification settings are required for [e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). Usage and invocation @@ -60,5 +73,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 Binary files differnew file mode 100644 index 0000000..dd0b1b6 --- /dev/null +++ b/doc/daily-psk.d/notification.avif diff --git a/doc/daily-psk.d/notification.svg b/doc/daily-psk.d/notification.svg deleted file mode 100644 index 77cf955..0000000 --- a/doc/daily-psk.d/notification.svg +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="443.78" height="213.78" version="1.1" viewBox="0 0 117.42 56.562" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="116.42" height="55.562" rx="1.4552" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.014 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan13351" x="180" y="10.85">[MikroTik] 📅 daily PSK Guest-Wifi -</tspan><tspan id="tspan13353" x="180" y="25.85"> -</tspan><tspan id="tspan13355" x="180" y="40.85">This is the daily PSK on MikroTik: -</tspan><tspan id="tspan13357" x="180" y="55.85"> -</tspan><tspan id="tspan13359" x="180" y="70.85">SSID: Guest-Wifi -</tspan><tspan id="tspan13361" x="180" y="85.85">PSK: S3cr3tStr1ng -</tspan><tspan id="tspan13363" x="180" y="100.85">Date: jun/17/2021 -</tspan><tspan id="tspan13365" x="180" y="115.85"> -</tspan><tspan id="tspan13367" x="180" y="130.85">A client device specific rule must not exist!</tspan></text> - <text id="text8530" x="2.6538308" y="34.683964" fill="#000000" font-family="sans-serif" font-size="3.175px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:2.38125px" xml:space="preserve"><tspan id="tspan25760" x="2.6538308" y="34.683964" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal">🔗 https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?</tspan><tspan id="tspan25762" x="2.6538308" y="39.528858" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal">scale=8&level=1&ssid=Guest-Wifi&pass=S3cr3tStr1ng</tspan></text> - </g> -</svg> diff --git a/doc/daily-psk.md b/doc/daily-psk.md index 62c26ee..f723617 100644 --- a/doc/daily-psk.md +++ b/doc/daily-psk.md @@ -1,7 +1,14 @@ Use wireless network with daily psk =================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -14,28 +21,35 @@ passphrase to a pseudo-random string daily. ### Sample notification -![daily-psk notification](daily-psk.d/notification.svg) +![daily-psk notification](daily-psk.d/notification.avif) Requirements and installation ----------------------------- Just install this script. -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +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: -For CAPsMAN: +For `wifi`: - $ScriptInstallUpdate daily-psk.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; -For local interface: +For legacy CAPsMAN: - $ScriptInstallUpdate daily-psk.local; + $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; -And add schedulers to run the script: +For legacy local interface: - /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 daily-psk.local;" start-time=startup; + $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; These will update the passphrase on boot and nightly at 3:00. @@ -47,15 +61,28 @@ 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 -Then add an access list entry: +> ℹ️ **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. For `wifi`: + + /interface/wifi/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily"; + +For legacy CAPsMAN: + + /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), -[matrix](mod/notification-matrix.md) and/or +[trix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.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 bb9222e..4831b8c 100644 --- a/doc/dhcp-lease-comment.md +++ b/doc/dhcp-lease-comment.md @@ -1,7 +1,14 @@ Comment DHCP leases with info from access list ============================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -15,14 +22,19 @@ from wireless access list. Requirements and installation ----------------------------- -Depending on whether you use CAPsMAN (`/caps-man`) or local wireless -interface (`/interface/wireless`) you need to install a different script. +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. + +For `wifi`: + + $ScriptInstallUpdate dhcp-lease-comment.wifi; -For CAPsMAN: +For legacy CAPsMAN: $ScriptInstallUpdate dhcp-lease-comment.capsman; -For local interface: +For legacy local interface: $ScriptInstallUpdate dhcp-lease-comment.local; @@ -48,5 +60,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 bde7f12..e7f3b88 100644 --- a/doc/dhcp-to-dns.md +++ b/doc/dhcp-to-dns.md @@ -1,7 +1,14 @@ Create DNS records for DHCP leases ================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -9,7 +16,9 @@ Create DNS records for DHCP leases Description ----------- -This script adds (and removes) dns records based on dhcp server leases. +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. Requirements and installation ----------------------------- @@ -32,12 +41,44 @@ 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 `global-config-overlay`, these are the parameters: +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: * `Domain`: the domain used for dns records -* `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 + +> ℹ️ **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. See also -------- @@ -48,5 +89,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/firmware-upgrade-reboot.md b/doc/firmware-upgrade-reboot.md index 0215ce9..420dfe1 100644 --- a/doc/firmware-upgrade-reboot.md +++ b/doc/firmware-upgrade-reboot.md @@ -1,7 +1,14 @@ Automatically upgrade firmware and reboot ========================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -32,5 +39,5 @@ See also * [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/fw-addr-lists.md b/doc/fw-addr-lists.md new file mode 100644 index 0000000..70ca6e9 --- /dev/null +++ b/doc/fw-addr-lists.md @@ -0,0 +1,128 @@ +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.12-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 +lists from [abuse.ch](https://abuse.ch/) and +[dshield.org](https://dshield.org/), 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. + +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. Some certificates are +available in my repository and downloaded automatically. Import it manually +(menu `/certificate/`) if missing. + +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! + +--- +[⬅️ 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 ac3e5cc..a3fe6d6 100644 --- a/doc/global-wait.md +++ b/doc/global-wait.md @@ -1,7 +1,14 @@ Wait for global functions and modules ===================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -36,5 +43,5 @@ See also * [Manage VLANs on bridge ports](mod/bridge-port-vlan.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 c7d28f6..03f79a7 100644 --- a/doc/gps-track.md +++ b/doc/gps-track.md @@ -1,7 +1,14 @@ Send GPS position to server =========================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -32,9 +39,13 @@ 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 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 211d4fb..6ce4421 100644 --- a/doc/hotspot-to-wpa.md +++ b/doc/hotspot-to-wpa.md @@ -1,7 +1,14 @@ -Use WPA2 network with hotspot credentials -========================================= +Use WPA network with hotspot credentials +======================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -10,37 +17,56 @@ Description ----------- RouterOS supports an unlimited number of MAC address specific passphrases -for WPA2 encrypted wifi networks via access list. The idea of this script -is to transfer hotspot credentials to MAC address specific WPA2 passphrase. +for WPA encrypted wifi networks via access list. The idea of this script +is to transfer hotspot credentials to MAC address specific WPA passphrase. Requirements and installation ----------------------------- -You need a properly configured hotspot on one (open) SSID and a WP2 enabled +You need a properly configured hotspot on one (open) SSID and a WPA enabled SSID with suffix "`-wpa`". -Then install the script: +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. + +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: - /ip/hotspot/user/profile/set on-login=hotspot-to-wpa [ find ]; + $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: +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; - $ScriptInstallUpdate hotspot-to-wpa-cleanup,lease-script; +For legacy CAPsMAN: -Create a scheduler: + $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; - /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup;" 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`. -And add the lease script to your wpa interfaces' dhcp server: + /ip/dhcp-server/set lease-script=lease-script comment="hotspot-to-wpa=wpa" hotspot-to-wpa; - /ip/dhcp-server/set lease-script=lease-script [ find where name~"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; Configuration ------------- @@ -54,17 +80,25 @@ 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 -* `private-passphrase`: do **not** use passphrase from hotspot's user - credentials, but given one - or unset (use default passphrase) with - special word `ignore` +* `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 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; @@ -77,7 +111,7 @@ Usage and invocation -------------------- Now let the users connect and login to the hotspot. After that the devices -(identified by MAC address) can connect to the WPA2 network, using the +(identified by MAC address) can connect to the WPA network, using the passphrase from hotspot credentials. See also @@ -86,5 +120,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/ip-addr-bridge.md b/doc/ip-addr-bridge.md index f0b593e..8bb9811 100644 --- a/doc/ip-addr-bridge.md +++ b/doc/ip-addr-bridge.md @@ -1,7 +1,14 @@ Manage IP addresses with bridge status ====================================== -[◀ Go back to main README](../README.md) +[![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.12-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) Description ----------- @@ -28,5 +35,5 @@ 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 index 87ad21a..ca5b86c 100644 --- a/doc/ipsec-to-dns.md +++ b/doc/ipsec-to-dns.md @@ -1,7 +1,14 @@ Create DNS records for IPSec peers ================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -36,11 +43,15 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `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) +[⬅️ 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 7c5a943..a5661fc 100644 --- a/doc/ipv6-update.md +++ b/doc/ipv6-update.md @@ -1,7 +1,14 @@ Update configuration on IPv6 prefix change ========================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -11,7 +18,7 @@ Description With changing IPv6 prefix from ISP this script handles to update... -* ipv6 firewall address-list +* ipv6 firewall address-list (prefixes (`/64`) and host addresses (`/128`)) * dns records Requirements and installation @@ -52,6 +59,11 @@ 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; + 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: @@ -64,5 +76,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 a435d43..f346621 100644 --- a/doc/lease-script.md +++ b/doc/lease-script.md @@ -1,7 +1,14 @@ Run other scripts on DHCP lease =============================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -40,8 +47,8 @@ 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 WPA2 network with hotspot credentials](hotspot-to-wpa.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 65f9f01..5dd5f63 100644 --- a/doc/leds-mode.md +++ b/doc/leds-mode.md @@ -1,7 +1,14 @@ Manage LEDs dark mode ===================== -[◀ Go back to main README](../README.md) +[![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.12-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) Description ----------- @@ -46,5 +53,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 Binary files differnew file mode 100644 index 0000000..a0f9ab3 --- /dev/null +++ b/doc/log-forward.d/notification.avif diff --git a/doc/log-forward.d/notification.svg b/doc/log-forward.d/notification.svg deleted file mode 100644 index 9527411..0000000 --- a/doc/log-forward.d/notification.svg +++ /dev/null @@ -1,37 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="573.78" height="203.78" version="1.1" viewBox="0 0 151.81 53.917" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="150.81" height="52.917" rx="1.8852" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.95 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2317" x="180" y="10.85">[MikroTik] ⚠ Log Forwarding -</tspan><tspan id="tspan2319" x="180" y="26.082813"> -</tspan><tspan id="tspan2321" x="180" y="41.082813">The log on MikroTik contains these 3 messages after 6d23:55:18 </tspan><tspan id="tspan2323" x="180" y="56.082811">uptime. -</tspan><tspan id="tspan2325" x="180" y="71.082811"> -</tspan><tspan id="tspan2327" x="180" y="86.082811"> ● 13:24:02 script;error backup-cloud: Failed uploading backup </tspan><tspan id="tspan2329" x="180" y="101.08281">for MikroTik to cloud! -</tspan><tspan id="tspan2331" x="180" y="116.08281"> ● 13:24:17 system;info;account user admin logged in from </tspan><tspan id="tspan2333" x="180" y="131.08281">192.168.88.177 via ssh -</tspan><tspan id="tspan2335" x="180" y="146.08282"> ● 13:24:57 system;info;account user admin logged out from </tspan><tspan id="tspan2337" x="180" y="161.08282">192.168.88.177 via ssh</tspan></text> - </g> -</svg> diff --git a/doc/log-forward.md b/doc/log-forward.md index 40a4135..4183d7b 100644 --- a/doc/log-forward.md +++ b/doc/log-forward.md @@ -1,7 +1,14 @@ Forward log messages via notification ===================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -9,20 +16,28 @@ Forward log messages via notification Description ----------- -RouterOS supports sending log messages via e-mail or to a syslog server. -This has some limitation, however: +RouterOS itself supports sending log messages via e-mail or to a syslog +server (see `/system/logging`). This has some limitation, however: * does not work early after boot if network connectivity is not - yet established + yet established, or breaks intermittently * lots of messages generate a flood of mails * Matrix and Telegram are not supported -The script is intended to be run periodically. It collects log messages -and forwards them via notification. +The script works around the limitations, for example it does: + +* read from `/log`, including messages from early boot +* skip multi-repeated messages +* rate-limit itself to mitigate flooding +* forward via notification (which includes *e-mail*, *Matrix* and *Telegram* + when installed and configured, see below) + +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.svg) +![log-forward notification](log-forward.d/notification.avif) Requirements and installation ----------------------------- @@ -46,11 +61,35 @@ The configuration goes to `global-config-overlay`, these are the parameters: * `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) and/or +[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`. + --- -[◀ 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 index f86b21d..838d1e0 100644 --- a/doc/mod/bridge-port-to.md +++ b/doc/mod/bridge-port-to.md @@ -1,7 +1,14 @@ Manage ports in bridge ====================== -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -77,5 +84,5 @@ See also * [Manage VLANs on bridge ports](bridge-port-vlan.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/mod/bridge-port-vlan.md b/doc/mod/bridge-port-vlan.md index 0e6c28f..5660b9d 100644 --- a/doc/mod/bridge-port-vlan.md +++ b/doc/mod/bridge-port-vlan.md @@ -1,7 +1,14 @@ Manage VLANs on bridge ports ============================ -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -81,5 +88,5 @@ See also * [Manage ports in bridge](bridge-port-to.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/mod/inspectvar.md b/doc/mod/inspectvar.md index 7782c8a..7ec74f2 100644 --- a/doc/mod/inspectvar.md +++ b/doc/mod/inspectvar.md @@ -1,7 +1,14 @@ Inspect variables ================= -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -29,5 +36,5 @@ Call the function `$InspectVar` with a variable as parameter: ![InspectVar](inspectvar.d/inspectvar.avif) --- -[◀ 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/ipcalc.md b/doc/mod/ipcalc.md index a3e7fc8..5b24952 100644 --- a/doc/mod/ipcalc.md +++ b/doc/mod/ipcalc.md @@ -1,7 +1,14 @@ IP address calculation ====================== -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -49,5 +56,5 @@ the information in a named array. ![IPCalcReturn](ipcalc.d/ipcalcreturn.avif) --- -[◀ 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/notification-email.md b/doc/mod/notification-email.md index 4e0ba04..76816c1 100644 --- a/doc/mod/notification-email.md +++ b/doc/mod/notification-email.md @@ -1,7 +1,14 @@ Send notifications via e-mail ============================= -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -26,10 +33,16 @@ 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 @@ -42,22 +55,34 @@ 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 send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: - $SendEMail "Subject..." "Body..." + $SendEMail "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $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) +[⬅️ 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 Binary files differnew file mode 100644 index 0000000..1db516b --- /dev/null +++ b/doc/mod/notification-matrix.d/01-authenticate.avif diff --git a/doc/mod/notification-matrix.d/01-home-server.avif b/doc/mod/notification-matrix.d/01-home-server.avif Binary files differdeleted file mode 100644 index 683c7b5..0000000 --- a/doc/mod/notification-matrix.d/01-home-server.avif +++ /dev/null diff --git a/doc/mod/notification-matrix.d/02-access-token.avif b/doc/mod/notification-matrix.d/02-access-token.avif Binary files differdeleted file mode 100644 index 54109a6..0000000 --- a/doc/mod/notification-matrix.d/02-access-token.avif +++ /dev/null diff --git a/doc/mod/notification-matrix.d/02-join-room.avif b/doc/mod/notification-matrix.d/02-join-room.avif Binary files differnew file mode 100644 index 0000000..edd6c81 --- /dev/null +++ b/doc/mod/notification-matrix.d/02-join-room.avif diff --git a/doc/mod/notification-matrix.d/03-join-room.avif b/doc/mod/notification-matrix.d/03-join-room.avif Binary files differdeleted file mode 100644 index 45974b8..0000000 --- a/doc/mod/notification-matrix.d/03-join-room.avif +++ /dev/null diff --git a/doc/mod/notification-matrix.md b/doc/mod/notification-matrix.md index b1f520e..c68b0aa 100644 --- a/doc/mod/notification-matrix.md +++ b/doc/mod/notification-matrix.md @@ -1,7 +1,14 @@ Send notifications via Matrix ============================= -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -21,8 +28,8 @@ Just install the module: $ScriptInstallUpdate mod/notification-matrix; Also install a Matrix client on at least one of your mobile and/or desktop -devices. As there is no privilege separation you should create a dedicated -notification account, in addition to your general user account. +devices. Create and setup an account there, we will reference that as +"*general account*" later. Configuration ------------- @@ -31,58 +38,57 @@ Edit `global-config-overlay`, add `MatrixHomeServer`, `MatrixAccessToken` and `MatrixRoom` - see below on hints how to retrieve this information. Then reload the configuration. -### Home server +> ℹ️ **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. -Matrix user accounts are identified by a unique user id in the form of -`@localpart:domain`. The `domain` part is not necessarily your home server -address, you have to resolve it with the procedure described in the -[Matrix specification](https://spec.matrix.org/latest/client-server-api/#server-discovery). +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. -Your best bet is to query the server at `domain` with the -[well-known uri](https://spec.matrix.org/latest/client-server-api/#well-known-uri). -For "*matrix.org*" this query is: +> ℹ️ **Info**: The *matrix.org* server uses a Cloudflare certificate. You can +> install that with: `$CertificateAvailable "Cloudflare Inc ECC CA-3"` - /tool/fetch "https://matrix.org/.well-known/matrix/client" output=user; +### From other device -![home server](notification-matrix.d/01-home-server.avif) +If you have setup your Matrix *notification account* before just reuse that. +Copy the relevant configuration to the device to be configured. -So the home server for "*matrix.org*" is "*matrix-client.matrix.org*". -Please strip the protocol ("*https://*") for `MatrixHomeServer` if given. +### Setup new account -### Access token +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. -After discovering the correct home server an access token has to be created. -For this the login credentials (username and password) of the notification -account must be sent to the home server via -[client server api](https://matrix.org/docs/guides/client-server-api#login). +#### Authenticate -We use the home server discovered above, "*matrix-client.matrix.org*". -The user is "*example*" and password is "*v3ry-s3cr3t*". +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: - /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/login" http-method=post http-data="{\"type\":\"m.login.password\", \"user\":\"example\", \"password\":\"v3ry-s3cr3t\"}" output=user; + $SetupMatrixAuthenticate "@example:matrix.org" "v3ry-s3cr3t"; -![access token](notification-matrix.d/02-access-token.avif) +![authenticate](notification-matrix.d/01-authenticate.avif) -The server replied with a JSON object containing the `access_token`, use that -for `MatrixAccessToken`. +#### Join Room -### 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). -Every Matix chat is a room, so we have to create one. Do so with your general -user, this makes sure your general user is the room owner. Then join the room -and invite the notification user by its user id "*@example:matrix.org*". Look -up the room id within the Matrix client, it should read like -"*!WUcxpSjKyxSGelouhA:matrix.org*". Use that for `MatrixRoom`. +Finally make the *notification account* join into the room by accepting +the invite. -Finally join the notification user to the room by accepting the invite. Again, -this can be done with -[client server api](https://matrix.org/docs/guides/client-server-api#joining-a-room-via-an-invite). -Make sure to replace room id ("*!*" is escaped with "*%21*") and access token -with your data. + $SetupMatrixJoinRoom "!WUcxpSjKyxSGelouhA:matrix.org"; - /tool/fetch "https://matrix-client.matrix.org/_matrix/client/r0/rooms/%21WUcxpSjKyxSGelouhA:matrix.org/join?access_token=yt_ZXdvcm0tdGVzdA_NNqUyvKHRhBLZmnzVVSK_0xu6yN" http-method=post http-data="" output=user; +![join room](notification-matrix.d/02-join-room.avif) -![join room](notification-matrix.d/03-join-room.avif) +The settings have been appended to `global-config-overlay`. You may want to +edit to move it to an appropriate place. Usage and invocation -------------------- @@ -90,22 +96,34 @@ 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 send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: - $SendMatrix "Subject..." "Body..." + $SendMatrix "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $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 -------- * [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) +[⬅️ 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 new file mode 100644 index 0000000..a3fdf88 --- /dev/null +++ b/doc/mod/notification-ntfy.md @@ -0,0 +1,86 @@ +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.12-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. + +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 +-------- + +* [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/setuserpic.avif b/doc/mod/notification-telegram.d/setuserpic.avif Binary files differnew file mode 100644 index 0000000..2017d20 --- /dev/null +++ b/doc/mod/notification-telegram.d/setuserpic.avif diff --git a/doc/mod/notification-telegram.md b/doc/mod/notification-telegram.md index 2b1abe9..cb326f0 100644 --- a/doc/mod/notification-telegram.md +++ b/doc/mod/notification-telegram.md @@ -1,7 +1,14 @@ Send notifications via Telegram =============================== -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -41,6 +48,10 @@ Finally edit `global-config-overlay`, add `TelegramTokenId` with the token from *BotFather* and `TelegramChatId` with your id from *GetIDs Bot*. 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 and the @@ -53,22 +64,49 @@ 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 send notifications directly or use a function in your -own scripts. Give it a try: +But of course you can use the function to send notifications directly. Give +it a try: - $SendTelegram "Subject..." "Body..." + $SendTelegram "Subject..." "Body..."; Alternatively this sends a notification with all available and configured methods: - $SendNotification "Subject..." "Body..." + $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) +[⬅️ Go back to main README](../../README.md) +[⬆️ Go back to top](#top) diff --git a/doc/mod/scriptrunonce.md b/doc/mod/scriptrunonce.md index 6efa1b7..6619efb 100644 --- a/doc/mod/scriptrunonce.md +++ b/doc/mod/scriptrunonce.md @@ -1,7 +1,14 @@ Download script and run it once =============================== -[◀ Go back to main README](../../README.md) +[![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.12-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. @@ -27,9 +34,13 @@ 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 values are -prepended and appended. +with protocol `ftp://`, `http://`, `https://` or `sftp://`) the base-url is +prepended, and file extension `.rsc` and url-suffix are appended. Usage and invocation -------------------- @@ -44,5 +55,5 @@ The function `$ScriptRunOnce` expects an URL (or name if Giving multiple scripts is possible, separated by comma. --- -[◀ 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/ssh-keys-import.md b/doc/mod/ssh-keys-import.md new file mode 100644 index 0000000..3d81566 --- /dev/null +++ b/doc/mod/ssh-keys-import.md @@ -0,0 +1,73 @@ +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.12-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-rsa AAAAB3Nza...QYZk8= user" admin; + +Starting with RouterOS *7.12beta1* support for keys of type `ed25519` has +been added: + + $SSHKeysImport "ssh-ed25519 AAAAC3Nza...ZVugJT 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 ef7754c..22ec215 100644 --- a/doc/mode-button.md +++ b/doc/mode-button.md @@ -1,7 +1,14 @@ Mode button with multiple presses ================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -52,7 +59,11 @@ Configuration The configuration goes to `global-config-overlay`, these are the parameters: * `ModeButton`: an array with defined actions -* `ModeButtonLED`: led to give visual feedback +* `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. Usage and invocation -------------------- @@ -60,5 +71,5 @@ Usage and invocation 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 index 65d0488..e00ccd0 100644 --- a/doc/netwatch-dns.md +++ b/doc/netwatch-dns.md @@ -1,7 +1,14 @@ Manage DNS and DoH servers from netwatch ======================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -43,10 +50,19 @@ Giving a specific query url for DoH is possible: 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="dns.nextdns.io" address=199.247.16.158; + /tool/netwatch/add comment="doh" host=199.247.16.158; + +Be aware that you have to keep the ip address in sync with real world +manually! + Importing a certificate automatically is possible, at least if available in the repository (see `certs` sub directory). - /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=1.1.1.1; + /tool/netwatch/add comment="doh, doh-cert=DigiCert Global G2 TLS RSA SHA256 2020 CA1" host=1.1.1.1; /tool/netwatch/add comment="doh, doh-cert=DigiCert TLS Hybrid ECC SHA384 2020 CA1" host=9.9.9.9; /tool/netwatch/add comment="doh, doh-cert=GTS CA 1C3" host=8.8.8.8; @@ -74,5 +90,5 @@ See also * [Notify on host up and down](netwatch-notify.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/netwatch-notify.d/notification-01-down.avif b/doc/netwatch-notify.d/notification-01-down.avif Binary files differnew file mode 100644 index 0000000..894fb23 --- /dev/null +++ b/doc/netwatch-notify.d/notification-01-down.avif diff --git a/doc/netwatch-notify.d/notification-01-down.svg b/doc/netwatch-notify.d/notification-01-down.svg deleted file mode 100644 index 13988a3..0000000 --- a/doc/netwatch-notify.d/notification-01-down.svg +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="463.78" height="93.78" version="1.1" viewBox="0 0 122.71 24.812" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="121.71" height="23.812" rx="1.5214" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.214 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2277" x="180" y="10.85">[MikroTik] ❌ Netwatch Notify: example.com down -</tspan><tspan id="tspan2279" x="180" y="25.85"> -</tspan><tspan id="tspan2281" x="180" y="40.85">The host 'example.com' (93.184.216.34) is down -</tspan><tspan id="tspan2283" x="180" y="55.85">since jun/08/2021 06:55:03.</tspan></text> - </g> -</svg> diff --git a/doc/netwatch-notify.d/notification-02-up.avif b/doc/netwatch-notify.d/notification-02-up.avif Binary files differnew file mode 100644 index 0000000..9021a93 --- /dev/null +++ b/doc/netwatch-notify.d/notification-02-up.avif diff --git a/doc/netwatch-notify.d/notification-02-up.svg b/doc/netwatch-notify.d/notification-02-up.svg deleted file mode 100644 index 32dfbcc..0000000 --- a/doc/netwatch-notify.d/notification-02-up.svg +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="493.78" height="113.78" version="1.1" viewBox="0 0 130.65 30.104" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="129.65" height="29.104" rx="1.6206" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -45.214 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2242" x="180" y="10.85">[MikroTik] ✅ Netwatch Notify: example.com up -</tspan><tspan id="tspan2244" x="180" y="25.85"> -</tspan><tspan id="tspan2246" x="180" y="40.85">The host 'example.com' (93.184.216.34) is up -</tspan><tspan id="tspan2248" x="180" y="55.85">since jun/08/2021 07:01:00. -</tspan><tspan id="tspan2250" x="180" y="70.85">It was down for 6 checks since jun/08/2021 06:55:03.</tspan></text> - </g> -</svg> diff --git a/doc/netwatch-notify.md b/doc/netwatch-notify.md index 032106a..806bb3a 100644 --- a/doc/netwatch-notify.md +++ b/doc/netwatch-notify.md @@ -1,7 +1,14 @@ Notify on host up and down ========================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -17,8 +24,8 @@ optional parent host is not down to avoid false alerts. ### Sample notifications -![netwatch-notify notification down](netwatch-notify.d/notification-01-down.svg) -![netwatch-notify notification up](netwatch-notify.d/notification-02-up.svg) +![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 ----------------------------- @@ -38,6 +45,12 @@ 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 It is possible to run an up hook command (`up-hook`) or down hook command @@ -50,6 +63,9 @@ 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. +Getting the escaping right may be troublesome. Please consider adding a +script in `/system/script`, then running that from hook. + ### Count threshould The count threshould (default is 5 checks) is configurable as well: @@ -74,9 +90,9 @@ with a resolvable name: /tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; -But be warned: Dynamic updates will probably cause issues if the name has -more than one record in dns - a high rate of configuration changes (and flash -writes) at least. +This supports multiple A or AAAA 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. ### No notification on host down @@ -88,10 +104,19 @@ powered off, but accessibility is of interest. Go and get your coffee ☕️ before sending the print job. -Also notification settings are required for -[e-mail](mod/notification-email.md), -[matrix](mod/notification-matrix.md) and/or -[telegram](mod/notification-telegram.md). +### 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/"; Tips & Tricks ------------- @@ -151,5 +176,5 @@ See also * [Manage DNS and DoH servers from netwatch](netwatch-dns.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/ospf-to-leds.md b/doc/ospf-to-leds.md index 5ab5c75..a7d4e9a 100644 --- a/doc/ospf-to-leds.md +++ b/doc/ospf-to-leds.md @@ -1,7 +1,14 @@ Visualize OSPF state via LEDs ============================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -33,5 +40,5 @@ instance `default` via LED `user-led` set this: /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 57f02d9..fae3896 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -1,7 +1,14 @@ Manage system update ==================== -[◀ Go back to main README](../README.md) +[![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.13-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. @@ -16,8 +23,12 @@ 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 -* upload backup if [backup-upload](backup-upload.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 * schedule reboot at night Requirements and installation @@ -30,6 +41,21 @@ 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 -------------------- @@ -40,13 +66,13 @@ Alternatively run it manually: See also -------- -* [Notify on RouterOS update](check-routeros-update.md) * [Upload backup to Mikrotik cloud](backup-cloud.md) * [Send backup via e-mail](backup-email.md) -* [Save configuration to fallback partition](doc/backup-partition.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) --- -[◀ 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 7545c5e..418f05e 100644 --- a/doc/ppp-on-up.md +++ b/doc/ppp-on-up.md @@ -1,7 +1,14 @@ Run scripts on ppp connection ============================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -33,5 +40,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/sms-action.md b/doc/sms-action.md index d2e3252..18ca574 100644 --- a/doc/sms-action.md +++ b/doc/sms-action.md @@ -1,7 +1,14 @@ Act on received SMS =================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -28,6 +35,10 @@ 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; @@ -48,5 +59,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 Binary files differnew file mode 100644 index 0000000..01eb7ba --- /dev/null +++ b/doc/sms-forward.d/notification.avif diff --git a/doc/sms-forward.d/notification.svg b/doc/sms-forward.d/notification.svg deleted file mode 100644 index 4b94850..0000000 --- a/doc/sms-forward.d/notification.svg +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="svg8" width="443.78" height="123.78" version="1.1" viewBox="0 0 117.42 32.75" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata id="metadata5"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(16.375 11.083)"> - <rect id="rect857" x="-15.875" y="-10.583" width="116.42" height="31.75" rx="1.4552" fill="#e6e6e6" stroke="#6c5d53" stroke-linecap="round" stroke-linejoin="round"/> - <g id="g884" transform="matrix(.5 0 0 .5 -12.406 -7.1146)" stroke-width="2"> - <path id="path899" d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g id="g871"> - <g id="text837" stroke-width=".52916px" aria-label="#!rsc"> - <path id="path851" d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path id="path853" d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path id="path855" d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path id="path857" d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path id="path859" d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g id="g1542" transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".26458"> - <path id="path943" d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path id="path945" d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> - </g> - </g> - </g> - <text id="text4811" transform="matrix(.26458 0 0 .26458 -44.966 -6.6039)" x="-248.88142" fill="#000000" font-family="'Fira Mono', 'Roboto Mono', monospace" font-size="12px" letter-spacing="0px" stroke-width="1px" word-spacing="0px" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:15px;shape-inside:url(#rect4813);white-space:pre" xml:space="preserve"><tspan id="tspan2204" x="180" y="10.85">[MikroTik] 📨 SMS Forwarding from 7277 -</tspan><tspan id="tspan2206" x="180" y="25.85"> -</tspan><tspan id="tspan2208" x="180" y="40.85">Received this message by MikroTik from 7277: -</tspan><tspan id="tspan2210" x="180" y="55.85"> -</tspan><tspan id="tspan2212" x="180" y="70.85">On Jun/12/2021 13:44:10 GMT -0 type class-0: -</tspan><tspan id="tspan2214" x="180" y="85.85">Welcome to our network!</tspan></text> - </g> -</svg> diff --git a/doc/sms-forward.md b/doc/sms-forward.md index f75b78f..2fe9486 100644 --- a/doc/sms-forward.md +++ b/doc/sms-forward.md @@ -1,7 +1,14 @@ Forward received SMS ==================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -15,7 +22,7 @@ A broadband interface with SMS support is required. ### Sample notification -![sms-forward notification](sms-forward.d/notification.svg) +![sms-forward notification](sms-forward.d/notification.avif) Requirements and installation ----------------------------- @@ -31,13 +38,55 @@ Just install the script: Configuration ------------- +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) and/or +[matrix](mod/notification-matrix.md), +[ntfy](mod/notification-ntfy.md) and/or [telegram](mod/notification-telegram.md). -Also you have to enable receiving of SMS: - /tool/sms/set receive-enabled=yes; +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. See also -------- @@ -45,5 +94,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 d83311f..d1325aa 100644 --- a/doc/ssh-keys-import.md +++ b/doc/ssh-keys-import.md @@ -1,33 +1,2 @@ -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: - - grep -E '^ssh-rsa' authorized_keys | nl -nrz | while read num type key name; do echo $type $key $name > $num-$name.pub; done - ---- -[◀ Go back to main README](../README.md) -[▲ Go back to top](#top) +This script has been replaced by a module. Please see +[Import ssh keys for public key authentication](mod/ssh-keys-import.md). diff --git a/doc/super-mario-theme.md b/doc/super-mario-theme.md index 8142cda..ec59b39 100644 --- a/doc/super-mario-theme.md +++ b/doc/super-mario-theme.md @@ -1,7 +1,14 @@ Play Super Mario theme ====================== -[◀ Go back to main README](../README.md) +[![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.12-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) Description ----------- @@ -27,5 +34,5 @@ Just run the script to play: 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 Binary files differnew file mode 100644 index 0000000..ab75f78 --- /dev/null +++ b/doc/telegram-chat.d/01-chat-specific.avif diff --git a/doc/telegram-chat.d/02-chat-all.avif b/doc/telegram-chat.d/02-chat-all.avif Binary files differnew file mode 100644 index 0000000..ed1a389 --- /dev/null +++ b/doc/telegram-chat.d/02-chat-all.avif diff --git a/doc/telegram-chat.d/03-reply.avif b/doc/telegram-chat.d/03-reply.avif Binary files differnew file mode 100644 index 0000000..515853e --- /dev/null +++ b/doc/telegram-chat.d/03-reply.avif diff --git a/doc/telegram-chat.md b/doc/telegram-chat.md new file mode 100644 index 0000000..2a4af99 --- /dev/null +++ b/doc/telegram-chat.md @@ -0,0 +1,153 @@ +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.12-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 + +RouterOS is limited in reading file content to a size of about four +kilobytes. Reading larger files does just fail, and that is also the limit +for command output. + +### 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 63f2793..a6bf994 100644 --- a/doc/unattended-lte-firmware-upgrade.md +++ b/doc/unattended-lte-firmware-upgrade.md @@ -1,7 +1,14 @@ Install LTE firmware upgrade ============================ -[◀ Go back to main README](../README.md) +[![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.12-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) Description ----------- @@ -12,6 +19,7 @@ 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. @@ -42,5 +50,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 7e87743..fba2a65 100644 --- a/doc/update-gre-address.md +++ b/doc/update-gre-address.md @@ -1,7 +1,14 @@ Update GRE configuration with dynamic addresses =============================================== -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -37,5 +44,5 @@ certificate CN into the comment: /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 bfe8e25..5aca581 100644 --- a/doc/update-tunnelbroker.md +++ b/doc/update-tunnelbroker.md @@ -1,7 +1,14 @@ Update tunnelbroker configuration ================================= -[◀ Go back to main README](../README.md) +[![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.12-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. @@ -28,11 +35,10 @@ Configuration The configuration goes to interface's comment: - /interface/6to4/set comment="tunnelbroker, user=user, pass=s3cr3t, id=12345" tunnelbroker; - -Also enabling dynamic DNS in Mikrotik cloud is required: + /interface/6to4/set comment="tunnelbroker, user=user, id=12345, pass=s3cr3t" tunnelbroker; - /ip/cloud/set ddns-enabled=yes; +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. See also -------- @@ -40,5 +46,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/firmware-upgrade-reboot b/firmware-upgrade-reboot deleted file mode 100644 index 27bbe41..0000000 --- a/firmware-upgrade-reboot +++ /dev/null @@ -1,41 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: firmware-upgrade-reboot -# Copyright (c) 2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# install firmware upgrade, and reboot -# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md - -:local 0 "firmware-upgrade-reboot"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global VersionToNum; - -:local RouterBoard [ /system/routerboard/get ]; -:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ - $LogPrintExit2 info $0 ("Firmware is already up to date.") true; -} -:if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={ - $LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true; -} - -:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ - $LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ - " is available, upgrading.") false; - /system/routerboard/upgrade; -} - -:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ - message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ - :delay 1s; -} - -:local Uptime [ /system/resource/get uptime ]; -:if ($Uptime < 1m) do={ - :delay $Uptime; -} - -$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; -/system/reboot; diff --git a/firmware-upgrade-reboot.rsc b/firmware-upgrade-reboot.rsc new file mode 100644 index 0000000..038f74e --- /dev/null +++ b/firmware-upgrade-reboot.rsc @@ -0,0 +1,54 @@ +#!rsc by RouterOS +# RouterOS script: firmware-upgrade-reboot +# Copyright (c) 2022-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# install firmware upgrade, and reboot +# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ScriptLock; + :global VersionToNum; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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" . "."); + :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."); + :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={ } diff --git a/fw-addr-lists.d/allow b/fw-addr-lists.d/allow new file mode 100644 index 0000000..8b59ed7 --- /dev/null +++ b/fw-addr-lists.d/allow @@ -0,0 +1,3 @@ +# 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 new file mode 100644 index 0000000..5e9fef2 --- /dev/null +++ b/fw-addr-lists.d/block @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 0000000..3b31a94 --- /dev/null +++ b/fw-addr-lists.d/mikrotik @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 0000000..68775b4 --- /dev/null +++ b/fw-addr-lists.rsc @@ -0,0 +1,159 @@ +#!rsc by RouterOS +# RouterOS script: fw-addr-lists +# Copyright (c) 2023-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# download, import and update firewall address-lists +# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global FwAddrLists; + :global FwAddrListTimeOut; + + :global CertificateAvailable; + :global EitherOr; + :global FetchUserAgentStr; + :global LogPrint; + :global LogPrintOnce; + :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; + } + } + } + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 "no"; + :local Data false; + :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; + + :if ([ :len ($List->"cert") ] > 0) do={ + :set CheckCertificate "yes-without-crl"; + :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ + $LogPrint warning $ScriptName ("Downloading required certificate failed, trying anyway."); + } + } + + :for I from=1 to=5 do={ + :if ($Data = false) do={ + :do { + :set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ + http-header-field=({ [ $FetchUserAgentStr $ScriptName ] }) ($List->"url") as-value ]->"data"); + } on-error={ + :if ($I < 5) do={ + $LogPrint debug $ScriptName ("Failed downloading, " . $I . ". try: " . $List->"url"); + :delay (($I * $I) . "s"); + } + } + } + } + + :if ($Data = false) do={ + :set Data ""; + :set Failure true; + $LogPrint warning $ScriptName ("Failed downloading list from: " . $List->"url"); + } + + :if ([ :len $Data ] > 63000) do={ + $LogPrintOnce warning $ScriptName ("The list is huge and may be truncated: " . $List->"url"); + } + + :while ([ :len $Data ] != 0) do={ + :local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; + :local Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); + :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$" || \ + $Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ + :set ($IPv4Addresses->$Address) $TimeOut; + } + :if ($Address ~ "^[0-9a-zA-Z]*:[0-9a-zA-Z:\\.]+(/[0-9]{1,3})?\$" || \ + $Address ~ "^[\\.a-zA-Z0-9-]+\\.[a-zA-Z]{2,}\$") do={ + :set ($IPv6Addresses->$Address) $TimeOut; + } + :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; + } + } + + :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :local Address [ /ip/firewall/address-list/get $Entry address ]; + :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={ + $LogPrint debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address); + /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address); + :set ($IPv4Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrint debug $ScriptName ("Removing IPv4 address: " . $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 ]; + :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={ + $LogPrint debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address); + /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address); + :set ($IPv6Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrint debug $ScriptName ("Removing: " . $Address); + /ipv6/firewall/address-list/remove $Entry; + :set CntRemove ($CntRemove + 1); + } + } + } + + :foreach Address,Timeout in=$IPv4Addresses do={ + $LogPrint debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address); + :do { + /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + :set ($IPv4Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrint warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'."); + } + } + + :foreach Address,Timeout in=$IPv6Addresses do={ + $LogPrint debug $ScriptName ("Adding IPv6 address for " . $Timeout . ": " . $Address); + :do { + /ipv6/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout; + :set ($IPv6Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrint warning $ScriptName ("Failed to add IPv6 address " . $Address . " to list '" . $FwListName . "'."); + } + } + + $LogPrint info $ScriptName ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove); + } +} on-error={ } diff --git a/global-config-overlay b/global-config-overlay deleted file mode 100644 index 70d8570..0000000 --- a/global-config-overlay +++ /dev/null @@ -1,11 +0,0 @@ -# Overlay for global configuration by RouterOS Scripts -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# global configuration, custom overlay -# https://git.eworm.de/cgit/routeros-scripts/about/ - -# Copy configuration from global-config, paste and modify it here. - - -# End of global-config-overlay diff --git a/global-config-overlay.rsc b/global-config-overlay.rsc new file mode 100644 index 0000000..9ffd90c --- /dev/null +++ b/global-config-overlay.rsc @@ -0,0 +1,12 @@ +# Overlay for global configuration by RouterOS Scripts +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# global configuration, custom overlay +# https://git.eworm.de/cgit/routeros-scripts/about/#editing-configuration + +# Copy relevant configuration from global-config, paste and modify it here. +# https://git.eworm.de/cgit/routeros-scripts/about/global-config.rsc + + +# End of global-config-overlay diff --git a/global-config.changes b/global-config.changes deleted file mode 100644 index 4bd302f..0000000 --- a/global-config.changes +++ /dev/null @@ -1,112 +0,0 @@ -# News, changes and migration by RouterOS Scripts -# Copyright (c) 2019-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global IfThenElse; -:global RequiredRouterOS; - -# 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."; - 43="Added queue for e-mail notifications to resend later on error."; - 44="Dropped script 'global-wait', all scripts wait on their own now."; - 45="We have a Telegram Group! Come along and say hello: https://t.me/routeros_scripts"; - 46="Added configurable random delay in backup scripts to stretch execution and prevent resource congestion."; - 47="Removed obsolete intermediate certificate 'Let's Encrypt Authority X3' from store."; - 48="Added support for overriding e-mail and Telegram settings for every script."; - 49="Dropped '\$EmailBackupTo' & '\$EmailBackupCc' from configuration, use settings override if required."; - 50="Added support for dynamic address update in 'netwatch-notify'."; - 51="Added 'ipsec-to-dns' to add DNS records for IPSec peers from mode-config."; - 52="Updated Let's Encrypt trust chain to use root certificate 'ISRG Root X1'. Do not re-import the old chain!"; - 53="Added support to send notifications via Matrix."; - 54="Support for Telegram notifications moved to a module. It is installed automatically if required."; - 55="Added reverse logic in 'log-forward', so messages can be included even if filtered before."; - 56="Added tags in all backup, lease and ppp-on-up scripts. These are used by 'packages-update', 'lease-script' and 'ppp-on-up' to find the scripts."; - 57="Celebrating the 1.000th commit - Hooray!"; - 58="Added a cleanup script for 'hotspot-to-wpa' to purge old access list entries."; - 59="Updating CAP with 'check-routeros-update' is now possible with opt-in."; - 60="Implemented a pre-down hook in 'netwatch-notify' that fires at two thirds of failed checks."; - 61="Finally removed old scripts."; - 62="Added '\$ScriptRunOnce' to run a script from URL once without installation, intended to aid configuration management and the like."; - 63="Moved optional functions '\$IPCalc' and '\$ScriptRunOnce' to modules."; - 64="Implemented '\$InspectVar' in module to inspect variables."; - 65="Added module to manage VLANs on bridge ports."; - 66="Moved script 'bridge-port-to-default' to new module."; - 67="Moved modules to directory with shorter name."; - 68="Reintroduced 'global-wait' for functions in scheduler."; - 69="Support hard lower limit for voltage in 'check-health'."; - 70="MikroTik started pushing RouterOS v7. Changes are no longer required."; - 71="MikroTik is pushing RouterOS v7 even more, in parallel branches. If you want to keep RouterOS v6 for some time see https://git.eworm.de/cgit/routeros-scripts/about/#requirements"; - 72="Introduced new script 'netwatch-dns' to manage DNS and DoH servers from netwatch."; - 73="Renamed backup scripts ('cloud-backup' -> 'backup-cloud', 'email-backup' -> 'backup-email', 'upload-backup' -> 'backup-upload')."; - 74="Extended 'hotspot-to-wpa', it can now read additional configuration from templates and hotspot users."; - 75=("Finally merged the RouterOS v7 code into the main branch. " . [ $IfThenElse ([ $RequiredRouterOS "global-config.changes" "7.0" false ] = true) \ - ("You may now drop '\$ScriptUpdatesUrlSuffix' from 'global-config-overlay'.") \ - ("Still running RouterOS v6, so last reminder to see https://git.eworm.de/cgit/routeros-scripts/about/#requirements") ]); - 76="Added an option to suppress notifications on host down with 'netwatch-notify'."; - 77="Introduced new script 'firmware-upgrade-reboot'. Handle with care!"; - 78="New documentation is online for notifications via Telegram & Matrix, variable inspection, ip address calculation and running scripts once."; - 79="Introduced new script 'backup-partition' to save configuration to fallback partition."; - 80="The 'routeros-v7' branch will now freeze, and vanish any time in future. You already switched to 'main' branch, well done!"; - 81="Dropped script 'rotate-ntp', as the limitation does no longer exist."; - 82="Renamed the comment parameter 'hostname' to just 'name' for 'netwatch-notify'."; - 83="Introduced new setting to disable news and change notifications, dropped version from configuration."; - 84="Support for e-mail notifications moved to a module. It is installed automatically if required."; - 85="Dropped 'netwatch-syslog', filtering in firewall is advised."; -}; - -# Migration steps to be applied on script updates -:global GlobalConfigMigration { - 41=":global SendNotification; \$SendNotification (\"Migration mechanism\") (\"Congratulations!\nSuccessfully tested the new migration mechanism.\");"; - 47="/certificate/remove [ find where fingerprint=\"731d3d9cfaa061487a1d71445a42f67df0afca2a6c2d2f98ff7b3ce112b1f568\" or fingerprint=\"25847d668eb4f04fdd40b12b6b0740c567da7d024308eb6c2c96fe41d9de218d\" ];"; - 52=":global CertificateDownload; :if ([ :len [ /certificate/find where fingerprint=\"67add1166b020ae61b8f5fc96813c04c2aa589960796865572a3c7e737613dfd\" or fingerprint=\"96bcec06264976f37460779acf28c5a7cfe8a3c0aae11a8ffcee05c0bddf08c6\" ] ] < 2) do={ \$CertificateDownload \"R3\"; }; /certificate/remove [ find where fingerprint=\"0687260331a72403d909f105e69bcf0d32e1bd2493ffc6d9206d11bcd6770739\" ];"; - 54=":global ScriptInstallUpdate; :global TelegramTokenId; :global TelegramChatId; :if ([ :len \$TelegramTokenId ] > 0 && [ :len \$TelegramChatId ] > 0) do={ \$ScriptInstallUpdate mod/notification-telegram; }"; - 61="/system/script/remove [ find where name~\"^(early-errors|mode-button-(event|scheduler)|script-updates)\\\$\" source~\"^#!rsc by RouterOS\\n\" ];"; - 66=":global ScriptInstallUpdate; :if ([ :len [ /system/script/find where name=\"bridge-port-to-default\" ] ] > 0) do={ /system/script/remove [ find where name~\"^bridge-port-to(-default|ggle)\\\$\" ]; \$ScriptInstallUpdate mod/bridge-port-to; }"; - 67=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Script in=[ /system/script/find where name~\"^global-functions.d/\" ] do={ /system/script/set name=[ \$CharacterReplace [ /system/script/get \$Script name ] \"global-functions.d/\" \"mod/\" ] \$Script; }; \$ScriptInstallUpdate;"; - 73=":global ScriptInstallUpdate; :global CharacterReplace; :foreach Old,New in={ \"cloud-backup\"=\"backup-cloud\"; \"email-backup\"=\"backup-email\"; \"upload-backup\"=\"backup-upload\" } do={ /system/script/set name=\$New [ find where name=\$Old ]; :foreach Scheduler in=[ /system/scheduler/find where on-event~\$Old ] do={ /system/scheduler/set \$Scheduler name=[ \$CharacterReplace [ get \$Scheduler name ] \$Old \$New ] on-event=[ \$CharacterReplace [ get \$Scheduler on-event ] \$Old \$New ]; }; }; \$ScriptInstallUpdate;"; - 81=":global NtpPool; :if ([ :len [ /system/script/find where name=\"rotate-ntp\" ] ] > 0) do={ /system/script/remove [ find where name=\"rotate-ntp\" ]; /system/scheduler/remove [ find where name=\"rotate-ntp\" ]; /system/ntp/client/set servers=\$NtpPool; };"; - 82=":global CharacterReplace; :foreach Netwatch in=[ /tool/netwatch/find where comment~\"notify\" !disabled ] do={ /tool/netwatch/set \$Netwatch comment=[ \$CharacterReplace [ get \$Netwatch comment ] \"hostname=\" \"name=\" ]; };"; - 84=":global ScriptInstallUpdate; :global EmailGeneralTo; :if ([ /tool/e-mail/get address ] != \"0.0.0.0\" && [ :len \$EmailGeneralTo ] > 0) do={ \$ScriptInstallUpdate mod/notification-email; }"; -}; diff --git a/global-config b/global-config.rsc index 6ed2a45..f393abb 100644 --- a/global-config +++ b/global-config.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: global-config -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # global configuration @@ -9,11 +9,12 @@ # Set this to 'true' to disable news and change notifications. :global NoNewsAndChangesNotification false; -# This is used for DNS and backup file. +# 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"; -:global HostNameInZone true; -:global PrefixInZone true; -:global ServerNameInZone false; # You can send e-mail notifications. Configure the system's mail settings # (/tool/e-mail), then install the module: @@ -32,8 +33,14 @@ :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; +# 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: @@ -45,9 +52,15 @@ #:global MatrixAccessToken "123456ABCDEFGHI..."; #:global MatrixRoom "!example:matrix.org"; -# It is possible to override e-mail, Telegram and Matrix setting for every -# script. This is done in arrays, where 'Override' is appended to the -# variable name, like this: +# You can send Ntfy notifications. Configure these settings and +# install the module: +# $ScriptInstallUpdate mod/notification-ntfy +:global NtfyServer "ntfy.sh"; +: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"; @@ -61,6 +74,7 @@ # 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. @@ -70,11 +84,38 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; +# This defines the settings for firewall address-lists (fw-addr-lists). +:global FwAddrLists { +# "allow"={ +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/allow"; +# cert="E1"; timeout=1w }; +# }; + "block"={ +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/block"; +# cert="E1" }; + { url="https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"; + cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; + { url="https://sslbl.abuse.ch/blacklist/sslipblacklist.txt"; + cert="GlobalSign Atlas R3 DV TLS CA 2022 Q3" }; + { url="https://www.dshield.org/block.txt"; cidr="/24"; + cert="R3" }; +# { url="https://www.spamhaus.org/drop/drop.txt"; +# cert="Cloudflare Inc ECC CA-3" }; +# { url="https://www.spamhaus.org/drop/edrop.txt"; +# cert="Cloudflare Inc ECC CA-3" }; + }; +# "mikrotik"={ +# { url="https://git.eworm.de/cgit/routeros-scripts/plain/fw-addr-lists.d/mikrotik"; +# cert="E1"; timeout=1w }; +# }; +}; +:global FwAddrListTimeOut 1d; + # This defines what log messages to filter or include by topic or message # text. Regular expressions are supported. Do *NOT* set an empty string, # that will filter or include everything! # These are filters, so excluding messages from forwarding. -:global LogForwardFilter "(debug|info)"; +:global LogForwardFilter "(debug|info|packet|raw)"; :global LogForwardFilterMessage []; #:global LogForwardFilterMessage "message text"; #:global LogForwardFilterMessage "(message text|another text|...)"; @@ -93,8 +134,13 @@ :global SafeUpdatePatch false; # Allow to install updates automatically if seen in neighbor list. :global SafeUpdateNeighbor false; -# Allow to install updates even if device is managed by CAPsMAN. -:global SafeUpdateOnCap 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. @@ -103,7 +149,7 @@ cpu-temperature=70; board-temperature1=50; board-temperature2=50; -} +}; # This is deviation on recovery threshold against notification flooding. :global CheckHealthTemperatureDeviation 3; :global CheckHealthVoltageLow 115; @@ -112,6 +158,7 @@ # 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"; @@ -125,7 +172,11 @@ "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 { @@ -147,11 +198,18 @@ # add more here... }; +# Run commands by hooking into SMS forward. +:global SmsForwardHooks { + { match="magic string"; + allowed-number="12345678"; + command="/system/script/run ..." }; +# add more here... +}; + # This is the address used to send gps data to. :global GpsTrackUrl "https://example.com/index.php"; -# Enable this to fetch scripts from given url. -:global ScriptUpdatesFetch true; +# This is the base url to fetch scripts from. :global ScriptUpdatesBaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; # alternative urls - main: stable code - next: currently in development #:global ScriptUpdatesBaseUrl "https://raw.githubusercontent.com/eworm-de/routeros-scripts/main/"; @@ -160,7 +218,7 @@ #:global ScriptUpdatesBaseUrl "https://gitlab.com/eworm-de/routeros-scripts/raw/next/"; :global ScriptUpdatesUrlSuffix ""; # use next branch with default url (git.eworm.de) -#:global ScriptUpdatesUrlSuffix "\?h=next"; +#:global ScriptUpdatesUrlSuffix "?h=next"; # Use this for defaults with $ScriptRunOnce # Install module with: @@ -182,16 +240,21 @@ :global CertRenewPass { "v3ry-s3cr3t"; "4n0th3r-s3cr3t"; -} +}; +:global CertWarnTime 2w; :global CertIssuedExportPass { "cert1-cn"="v3ry-s3cr3t"; "cert2-cn"="4n0th3r-s3cr3t"; -} +}; -# load custom settings from overlay +# load custom settings from overlay and snippets # Warning: Do *NOT* copy this code to overlay! -:do { - /system/script/run global-config-overlay; -} on-error={ - :log error ("Loading configuration from overlay failed!"); +: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.rsc index f4c47d7..1e98019 100644 --- a/global-functions +++ b/global-functions.rsc @@ -1,49 +1,65 @@ #!rsc by RouterOS # RouterOS script: global-functions -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # Michael Gisbers <michael@gisbers.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # global functions # https://git.eworm.de/cgit/routeros-scripts/about/ -:local 0 "global-functions"; +:local ScriptName [ :jobname ]; # expected configuration version -:global ExpectedConfigVersion 85; +:global ExpectedConfigVersion 124; # 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 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 LogPrintExit2; +:global LogPrintOnce; +:global MAX; +:global MIN; :global MkDir; :global NotificationFunctions; +:global ParseDate; +:global ParseJson; :global ParseKeyValueStore; :global PrettyPrint; -:global QuotedPrintable; :global RandomDelay; -:global Read; :global RequiredRouterOS; :global ScriptFromTerminal; :global ScriptInstallUpdate; @@ -52,6 +68,7 @@ :global SendNotification2; :global SymbolByUnicodeName; :global SymbolForNotification; +:global Unix2Dos; :global UrlEncode; :global ValidateSyntax; :global VersionToNum; @@ -61,23 +78,37 @@ :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 LogPrintExit2; + :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={ - $LogPrintExit2 warning $0 ("This system has low free flash space but " . \ - "is configured to download certificate CRLs to system!") false; + $LogPrint warning $0 ("This system has low free flash space but " . \ + "is configured to download certificate CRLs to system!"); } :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ - $LogPrintExit2 info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available.") false; + $LogPrint info $0 ("Certificate with CommonName \"" . $CommonName . "\" not available."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -86,8 +117,8 @@ :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={ - $LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ - "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; + $LogPrint info $0 ("Certificate chain for \"" . $CommonName . \ + "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\"."); :if ([ $CertificateDownload $CommonName ] = false) do={ :return false; } @@ -105,29 +136,28 @@ :global ScriptUpdatesUrlSuffix; :global CertificateNameByCN; - :global LogPrintExit2; - :global UrlEncode; + :global CleanName; + :global FetchUserAgentStr; + :global LogPrint; :global WaitForFile; - $LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ - "CommonName \"" . $CommonName . "\".") false; + $LogPrint info $0 ("Downloading and importing certificate with " . \ + "CommonName \"" . $CommonName . "\"."); :do { - :local LocalFileName ($CommonName . ".pem"); - :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); - /tool/fetch check-certificate=yes-without-crl \ - ($ScriptUpdatesBaseUrl . "certs/" . \ - $UrlFileName . $ScriptUpdatesUrlSuffix) \ - dst-path=$LocalFileName as-value; - $WaitForFile $LocalFileName; - /certificate/import file-name=$LocalFileName passphrase="" as-value; - /file/remove $LocalFileName; - - :foreach Cert in=[ /certificate/find where name~("^" . $LocalFileName . "_[0-9]+\$") ] do={ + :local FileName ([ $CleanName $CommonName ] . ".pem"); + /tool/fetch check-certificate=yes-without-crl http-header-field=({ [ $FetchUserAgentStr $0 ] }) \ + ($ScriptUpdatesBaseUrl . "certs/" . $FileName . $ScriptUpdatesUrlSuffix) \ + dst-path=$FileName as-value; + $WaitForFile $FileName; + /certificate/import file-name=$FileName passphrase="" as-value; + :delay 1s; + /file/remove $FileName; + + :foreach Cert in=[ /certificate/find where name~("^" . $FileName . "_[0-9]+\$") ] do={ $CertificateNameByCN [ /certificate/get $Cert common-name ]; } } on-error={ - $LogPrintExit2 warning $0 ("Failed importing certificate with " . \ - "CommonName \"" . $CommonName . "\"!") false; + $LogPrint warning $0 ("Failed importing certificate with CommonName \"" . $CommonName . "\"!"); :return false; } :return true; @@ -137,11 +167,19 @@ :set CertificateNameByCN do={ :local CommonName [ :tostr $1 ]; - :global CharacterReplace; + :global CleanName; :local Cert [ /certificate/find where common-name=$CommonName ]; - /certificate/set $Cert \ - name=[ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $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 @@ -183,43 +221,76 @@ :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={ + :set Char "-"; + } + :if ($Char != "-" || [ :pick $Return ([ :len $Return ] - 1) ] != "-") do={ + :set Return ($Return . $Char); + } + } + :return $Return; +} + # get readable device info :set DeviceInfo do={ :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 License [ /system/license/get ]; + :local Snmp [ /snmp/get ]; :local Update [ /system/package/update/get ]; :return ( \ - "Hostname: " . $Identity . \ - "\nBoard name: " . $Resource->"board-name" . \ - "\nArchitecture: " . $Resource->"architecture-name" . \ + [ $FormatLine "Hostname" $Identity ] . "\n" . \ + [ $IfThenElse ([ :len ($Snmp->"location") ] > 0) \ + ([ $FormatLine "Location" ($Snmp->"location") ] . "\n") ] . \ + [ $IfThenElse ([ :len ($Snmp->"contact") ] > 0) \ + ([ $FormatLine "Contact" ($Snmp->"contact") ] . "\n") ] . \ + [ $FormatLine "Board name" ($Resource->"board-name") ] . "\n" . \ + [ $FormatLine "Architecture" ($Resource->"architecture-name") ] . "\n" . \ [ $IfThenElse ($RouterBoard->"routerboard" = true) \ - ("\nModel: " . $RouterBoard->"model" . \ - [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ - (" " . $RouterBoard->"revision") ] . \ - "\nSerial number: " . $RouterBoard->"serial-number") ] . \ + ([ $FormatLine "Model" ($RouterBoard->"model") ] . \ + [ $IfThenElse ([ :len ($RouterBoard->"revision") ] > 0) \ + (" " . $RouterBoard->"revision") ] . "\n" . \ + [ $FormatLine "Serial number" ($RouterBoard->"serial-number") ] . "\n") ] . \ [ $IfThenElse ([ :len ($License->"level") ] > 0) \ - ("\nLicense: " . $License->"level") ] . \ - "\nRouterOS:" . \ - "\n Channel: " . $Update->"channel" . \ - "\n Installed: " . $Update->"installed-version" . \ + ([ $FormatLine "License" ($License->"level") ] . "\n") ] . \ + "RouterOS:\n" . \ + [ $FormatLine " Channel" ($Update->"channel") ] . "\n" . \ + [ $FormatLine " Installed" ($Update->"installed-version") ] . "\n" . \ [ $IfThenElse ([ :typeof ($Update->"latest-version") ] != "nothing" && \ $Update->"installed-version" != $Update->"latest-version") \ - ("\n Available: " . $Update->"latest-version") ] . \ + ([ $FormatLine " Available" ($Update->"latest-version") ] . "\n") ] . \ [ $IfThenElse ($RouterBoard->"routerboard" = true && \ $RouterBoard->"current-firmware" != $RouterBoard->"upgrade-firmware") \ - ("\n Firmware: " . $RouterBoard->"current-firmware") ] . \ - "\nRouterOS-Scripts:" . \ - "\n Version: " . $ExpectedConfigVersion); + ([ $FormatLine " Firmware" ($RouterBoard->"current-firmware") ] . "\n") ] . \ + "RouterOS-Scripts:\n" . \ + [ $FormatLine " Version" $ExpectedConfigVersion ]); +} + +# convert line endings, DOS -> UNIX +:set Dos2Unix do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace $Input ("\r\n") ("\n") ]; } # download package from upgrade server @@ -231,7 +302,7 @@ :global CertificateAvailable; :global CleanFilePath; - :global LogPrintExit2; + :global LogPrint; :global MkDir; :global WaitForFile; @@ -246,22 +317,23 @@ :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :if ([ $MkDir $PkgDir ] = false) do={ - $LogPrintExit2 warning $0 ("Failed creating directory, not downloading package.") false; + $LogPrint warning $0 ("Failed creating directory, not downloading package."); :return false; } :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ - $LogPrintExit2 info $0 ("Package file " . $PkgName . " already exists.") false; + $LogPrint info $0 ("Package file " . $PkgName . " already exists."); :return true; } :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; + $LogPrint error $0 ("Downloading required certificate failed."); + :return false; } :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile); - $LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; - $LogPrintExit2 debug $0 ("... from url: " . $Url) false; + $LogPrint info $0 ("Downloading package file '" . $PkgName . "'..."); + $LogPrint debug $0 ("... from url: " . $Url); :local Retry 3; :while ($Retry > 0) do={ :do { @@ -272,14 +344,14 @@ :return true; } } on-error={ - $LogPrintExit2 debug $0 ("Downloading package file failed.") false; + $LogPrint debug $0 ("Downloading package file failed."); } /file/remove [ find where name=$PkgDest ]; :set Retry ($Retry - 1); } - $LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; + $LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed."); :return false; } @@ -290,6 +362,9 @@ :if ([ :typeof $1 ] = "num") do={ :return [ $IfThenElse ($1 != 0) $1 $2 ]; } + :if ([ :typeof $1 ] = "time") do={ + :return [ $IfThenElse ($1 > 0s) $1 $2 ]; + } :return [ $IfThenElse ([ :len [ :tostr $1 ] ] > 0) $1 $2 ]; } @@ -302,7 +377,7 @@ } :local Return ""; - :local Chars ("^.[]\$()|*+\?{}\\"); + :local Chars ("^.[]\$()|*+?{}\\"); :for I from=0 to=([ :len $Input ] - 1) do={ :local Char [ :pick $Input $I ]; @@ -315,20 +390,73 @@ :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 LogPrintExit2; + :global IsMacLocallyAdministered; + :global LogPrint; - :if ([ :tonum ("0x" . [ :pick $Mac 0 [ :find $Mac ":" ] ]) ] & 2 = 2) do={ + :if ([ $IsMacLocallyAdministered $Mac ] = true) do={ :return "locally administered"; } :do { - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + :if ([ $CertificateAvailable "GTS CA 1P5" ] = 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"); @@ -337,9 +465,9 @@ :do { /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ output=none as-value; - $LogPrintExit2 debug $0 ("The mac vendor is not known in database.") false; + $LogPrint debug $0 ("The mac vendor is not known in database."); } on-error={ - $LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; + $LogPrint warning $0 ("Failed getting mac vendor."); } :return "unknown vendor"; } @@ -366,19 +494,67 @@ :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 ]; - :local Hex "0123456789abcdef0123456789ABCDEF"; - :local Multi 1; - :local Return 0; - :for I from=([ :len $Input ] - 1) to=0 do={ - :set Return ($Return + (([ :find $Hex [ :pick $Input $I ] ] % 16) * $Multi)); - :set Multi ($Multi * 16); + :global HexToNum; + + :if ([ :pick $Input 0 ] = "*") do={ + :return [ $HexToNum [ :pick $Input 1 [ :len $Input ] ] ]; } - :return $Return; + :return [ :tonum ("0x" . $Input) ]; +} + +# return human readable number +:set HumanReadableNum do={ + :local Input [ :tonum $1 ]; + :local Base [ :tonum $2 ]; + + :global EitherOr; + + :local Prefix "kMGTPE"; + :local Pow 1; + + :set Base [ $EitherOr $Base 1024 ]; + + :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); + } + :return ($Tmp2 . "." . [ :pick $Tmp1 [ :len $Tmp2 ] ([ :len $Tmp1 ] - [ :len $Tmp2 ] + 1) ] . $Prefix); + } + } } # mimic conditional/ternary operator (condition ? consequent : alternative) @@ -399,8 +575,6 @@ # check if DNS is resolving :set IsDNSResolving do={ - :global CharacterReplace; - :do { :resolve "low-ttl.eworm.de"; } on-error={ @@ -427,11 +601,20 @@ :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 LogPrintExit2; + :global LogPrint; :if ($IsTimeSyncCached = true) do={ :return true; @@ -442,9 +625,28 @@ :set IsTimeSyncCached true; :return true; } + + :if ([ :typeof $IsTimeSyncResetNtp ] = "nothing") do={ + :set IsTimeSyncResetNtp 0s; + } + :local Uptime [ /system/resource/get uptime ]; + :if ($Uptime - $IsTimeSyncResetNtp < 3m) do={ + :return false; + } + + :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={ + $LogPrint 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; @@ -453,16 +655,15 @@ :return false; } - $LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; + $LogPrint debug $0 ("No time source configured! Returning gracefully..."); :return true; } -# log and print with same text, optionally exit -:set LogPrintExit2 do={ +# log and print with same text +:set LogPrint do={ :local Severity [ :tostr $1 ]; :local Name [ :tostr $2 ]; :local Message [ :tostr $3 ]; - :local Exit [ :tostr $4 ]; :global PrintDebug; :global PrintDebugOverride; @@ -493,44 +694,126 @@ } :if ($Severity != "debug" || $Debug = true) do={ - :if ($Exit = "true") do={ - :error ([ $PrintSeverity $Severity ] . ": " . $Message); - } else={ - :put ([ $PrintSeverity $Severity ] . ": " . $Message); - } + :put ([ $PrintSeverity $Severity ] . ": " . $Message); } } +# log and print with same text, optionally exit +# Deprectated! - TODO: remove later +:set LogPrintExit2 do={ + :local Severity [ :tostr $1 ]; + :local Name [ :tostr $2 ]; + :local Message [ :tostr $3 ]; + :local Exit [ :tostr $4 ]; + + :global LogPrint; + :global LogPrintOnce; + + $LogPrintOnce warning $0 \ + ("This function is deprecated and will be removed. Please make your adjustments!"); + + $LogPrint $1 $2 $3; + + :if ($Exit = "true") do={ + :error ("Hard error to exit."); + } +} + +# 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; +} + +# 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 Dir [ :tostr $1 ]; + :local Path [ :tostr $1 ]; :global CleanFilePath; - :global GetRandom20CharHex; - :global LogPrintExit2; + :global LogPrint; :global WaitForFile; - :set Dir [ $CleanFilePath $Dir ]; + :local MkTmpfs do={ + :global LogPrint; + :global WaitForFile; - :if ($Dir = "") do={ + :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={ + :return true; + } + + $LogPrint info $0 ("Creating disk of type tmpfs."); + /file/remove [ find where name="tmpfs" type="directory" ]; + :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; } - :if ([ :len [ /file/find where name=$Dir type="directory" ] ] = 1) do={ + :set Path [ $CleanFilePath $Path ]; + + :if ($Path = "") do={ :return true; } - :local Return true; - :local Name ($Dir . "-" . [ $GetRandom20CharHex ]); + :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ + :return true; + } + + :if ([ :pick $Path 0 5 ] = "tmpfs") do={ + :if ([ $MkTmpfs ] = false) do={ + :return false; + } + } + :do { - /ip/smb/share/add disabled=yes directory=$Dir name=$Name; - $WaitForFile $Dir; + :local File ($Path . "/file"); + /file/add name=$File; + $WaitForFile $File; + /file/remove $File; } on-error={ - $LogPrintExit2 warning $0 ("Making directory '" . $Dir . "' failed!") false; - :set Return false; + $LogPrint warning $0 ("Making directory '" . $Path . "' failed!"); + :return false; } - /ip/smb/share/remove [ find where name=$Name ]; - :return $Return; + + :return true; } # prepare NotificationFunctions array @@ -538,6 +821,75 @@ :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 JSON into array +# Warning: This is not a complete parser! +:set ParseJson do={ + :local Input [ :tostr $1 ]; + + :local InLen; + :local Return ({}); + :local Skip 0; + + :if ([ :pick $Input 0 ] = "{") do={ + :set Input [ :pick $Input 1 ([ :len $Input ] - 1) ]; + } + :set Input [ :toarray $Input ]; + :set InLen [ :len $Input ]; + + :for I from=0 to=$InLen do={ + :if ($Skip > 0 || $Input->$I = "\n" || $Input->$I = "\r\n") do={ + :if ($Skip > 0) do={ + :set $Skip ($Skip - 1); + } + } else={ + :local Done false; + :local Key ($Input->$I); + :local Val1 ($Input->($I + 1)); + :local Val2 ($Input->($I + 2)); + :if ($Val1 = ":") do={ + :set Skip 2; + :set ($Return->$Key) $Val2; + :set Done true; + } + :if ($Done = false && $Val1 = ":[") do={ + :local Last false; + :set Skip 1; + :set ($Return->$Key) ({}); + :do { + :set Skip ($Skip + 1); + :local ValX ($Input->($I + $Skip)); + :if ([ :pick $ValX ([ :len $ValX ] - 1) ] = "]") do={ + :set Last true; + :set ValX [ :pick $ValX 0 ([ :len $ValX ] - 1) ]; + } + :set ($Return->$Key) (($Return->$Key), $ValX); + } while=($Last = false && $I + $Skip < $InLen); + :set Done true; + } + :if ($Done = false && $Val1 = ":[]") do={ + :set Skip 1; + :set ($Return->$Key) ({}); + :set Done true; + } + :if ($Done = false) do={ + :set Skip 1; + :set ($Return->$Key) [ :pick $Val1 1 [ :len $Val1 ] ]; + } + } + } + + :return $Return; +} + # parse key value store :set ParseKeyValueStore do={ :local Source $1; @@ -560,58 +912,25 @@ :set PrettyPrint do={ :local Input [ :tostr $1 ]; - :global CharacterReplace; - - :put [ $CharacterReplace $Input ("\n") ("\n\r") ]; -} - -# convert string to quoted-printable -:global QuotedPrintable do={ - :local Input [ :tostr $1 ]; - - :if ([ :len $Input ] = 0) do={ - :return $Input; - } - - :local Return ""; - :local Chars ("\80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\90\91\92\93\94\95\96\97" . \ - "\98\99\9A\9B\9C\9D\9E\9F\A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\B0\B1\B2\B3" . \ - "\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF" . \ - "\D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB" . \ - "\EC\ED\EE\EF\F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"); - :local Hex { "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "A"; "B"; "C"; "D"; "E"; "F" }; - - :for I from=0 to=([ :len $Input ] - 1) do={ - :local Char [ :pick $Input $I ]; - :local Replace [ :find $Chars $Char ]; - - :if ($Char = "=") do={ - :set Char "=3D"; - } - :if ([ :typeof $Replace ] = "num") do={ - :set Char ("=" . ($Hex->($Replace / 16 + 8)) . ($Hex->($Replace % 16))); - } - :set Return ($Return . $Char); - } + :global Unix2Dos; - :if ($Input = $Return) do={ - :return $Input; - } - - :return ("=\?utf-8\?Q\?" . $Return . "\?="); + :put [ $Unix2Dos $Input ]; } # delay a random amount of seconds :set RandomDelay do={ + :local Time [ :tonum $1 ]; + :local Unit [ :tostr $2 ]; + :global EitherOr; :global GetRandomNumber; + :global MAX; - :delay ([ $GetRandomNumber $1 ] . [ $EitherOr $2 "s" ]); -} + :if ($Time = 0) do={ + :return false; + } -# read input from user -:set Read do={ - :return; + :delay ([ $MAX 10 [ $GetRandomNumber ([ :tonsec [ :totime ($Time . [ $EitherOr $Unit "s" ]) ] ] / 1000000) ] ] . "ms"); } # check for required RouterOS version @@ -621,12 +940,18 @@ :local Warn [ :tostr $3 ]; :global IfThenElse; - :global LogPrintExit2; + :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={ - $LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ - " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; + $LogPrint warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ + " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!"); } :return false; } @@ -637,7 +962,7 @@ :set ScriptFromTerminal do={ :local Script [ :tostr $1 ]; - :global LogPrintExit2; + :global LogPrint; :foreach Job in=[ /system/script/job/find where script=$Script ] do={ :set Job [ /system/script/job/get $Job ]; @@ -645,11 +970,11 @@ :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; } :if (($Job->"type") = "login") do={ - $LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; + $LogPrint debug $0 ("Script " . $Script . " started from terminal."); :return true; } } - $LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; + $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal."); :return false; } @@ -663,30 +988,29 @@ :global Identity; :global IDonate; :global NoNewsAndChangesNotification; - :global NotificationsWithSymbols; :global ScriptUpdatesBaseUrl; - :global ScriptUpdatesFetch; :global ScriptUpdatesUrlSuffix; :global CertificateAvailable; + :global EitherOr; + :global FetchUserAgentStr; + :global Grep; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; + :global LogPrintOnce; :global ParseKeyValueStore; + :global RequiredRouterOS; :global SendNotification2; :global SymbolForNotification; :global ValidateSyntax; - :if ([ $CertificateAvailable "R3" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - :if ([ $CertificateAvailable "E1" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; + $LogPrint warning $0 ("Downloading certificate failed, trying without."); } :foreach Script in=$Scripts do={ :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 info $0 ("Adding new script: " . $Script) false; + $LogPrint info $0 ("Adding new script: " . $Script); /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment; } } @@ -695,46 +1019,37 @@ :local ReloadGlobalFunctions false; :local ReloadGlobalConfig false; - :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\n" ] do={ + :foreach Script in=[ /system/script/find where source~"^#!rsc by RouterOS\r?\n" ] do={ :local ScriptVal [ /system/script/get $Script ]; - :local ScriptFile [ /file/find where name=("script-updates/" . $ScriptVal->"name") ]; + :local ScriptInfo [ $ParseKeyValueStore ($ScriptVal->"comment") ]; :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={ - $LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ - "' and its scheduler '" . $SchedulerVal->"name" . "'!") false; + $LogPrint warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ + "' and its scheduler '" . $SchedulerVal->"name" . "'!"); } } - :if ([ :len $SourceNew ] = 0 && $ScriptUpdatesFetch = true) do={ - :local Comment [ $ParseKeyValueStore ($ScriptVal->"comment") ]; - :if (!($Comment->"ignore" = true)) do={ - :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 Url ($BaseUrl . $ScriptVal->"name" . $UrlSuffix); - - $LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; - :if ($Result->"status" = "finished") do={ - :set SourceNew ($Result->"data"); - } - } on-error={ - :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ - "', removing dummy. Typo on installation?") false; - /system/script/remove $Script; - } else={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; - } + :if (!($ScriptInfo->"ignore" = true)) do={ + :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 ($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" . "'!"); } } } @@ -742,64 +1057,77 @@ :if ([ :len $SourceNew ] > 0) do={ :if ($SourceNew != $ScriptVal->"source") do={ :if ([ :pick $SourceNew 0 18 ] = "#!rsc by RouterOS\n") do={ - :if ([ $ValidateSyntax $SourceNew ] = true) do={ - $LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; - /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; - :if ($ScriptVal->"name" = "global-config") do={ - :set ReloadGlobalConfig true; - } - :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ - :set ReloadGlobalFunctions true; + :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); + :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ + :if ([ $ValidateSyntax $SourceNew ] = true) do={ + $LogPrint info $0 ("Updating script: " . $ScriptVal->"name"); + /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; + :if ($ScriptVal->"name" = "global-config") do={ + :set ReloadGlobalConfig true; + } + :if ($ScriptVal->"name" = "global-functions" || $ScriptVal->"name" ~ ("^mod/.")) do={ + :set ReloadGlobalFunctions true; + } + } else={ + $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ + "' failed! Ignoring!"); } } else={ - $LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ - "' failed! Ignoring!") false; + $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ + $Required . ", which is not met by your installation. Ignoring!"); } } else={ - $LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ - "' is not valid (missing shebang). Ignoring!") false; + $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ + "' is not valid (missing shebang). Ignoring!"); } } else={ - $LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; + $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change."); } } else={ - $LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; + $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'."); } } :if ($ReloadGlobalFunctions = true) do={ - $LogPrintExit2 info $0 ("Reloading global functions.") false; + $LogPrint info $0 ("Reloading global functions."); :do { /system/script/run global-functions; } on-error={ - $LogPrintExit2 error $0 ("Reloading global functions failed!") false; + $LogPrint error $0 ("Reloading global functions failed!"); } } :if ($ReloadGlobalConfig = true) do={ - $LogPrintExit2 info $0 ("Reloading global configuration.") false; + $LogPrint info $0 ("Reloading global configuration."); :do { /system/script/run global-config; } on-error={ - $LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ - " Syntax error or missing overlay\?") false; + $LogPrint error $0 ("Reloading global configuration failed!" . \ + " Syntax error or missing overlay?"); } } - :if ($ExpectedConfigVersionBefore != $ExpectedConfigVersion) do={ + :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 . "global-config.changes" . $ScriptUpdatesUrlSuffix); - $LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; - :local Result [ /tool/fetch check-certificate=yes-without-crl $Url output=user as-value ]; + :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={ - $LogPrintExit2 warning $0 ("Failed fetching news, changes and migration!") false; + $LogPrint warning $0 ("Failed fetching news, changes and migration!"); } :if ([ :len $ChangeLogCode ] > 0) do={ @@ -807,10 +1135,10 @@ :do { [ :parse $ChangeLogCode ]; } on-error={ - $LogPrintExit2 warning $0 ("The changelog failed to run!") false; + $LogPrint warning $0 ("The changelog failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; + $LogPrint warning $0 ("The changelog failed syntax validation!"); } } @@ -819,14 +1147,14 @@ :local Migration ($GlobalConfigMigration->[ :tostr $I ]); :if ([ :typeof $Migration ] = "str") do={ :if ([ $ValidateSyntax $Migration ] = true) do={ - $LogPrintExit2 info $0 ("Applying migration for change " . $I . ": " . $Migration) false; + $LogPrint info $0 ("Applying migration for change " . $I . ": " . $Migration); :do { [ :parse $Migration ]; } on-error={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed to run!") false; + $LogPrint warning $0 ("Migration code for change " . $I . " failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; + $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!"); } } } @@ -835,15 +1163,15 @@ :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."); - $LogPrintExit2 info $0 ($NotificationMessage) false; + $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 " . \ - [ $IfThenElse ($NotificationsWithSymbols = true) ("\E2\97\8F") "*" ] . " " . $Change); - $LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; + [ $SymbolForNotification "pushpin" "*" ] . $Change); + $LogPrint info $0 ("Change " . $I . ": " . $Change); } } else={ :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); @@ -857,7 +1185,7 @@ "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"; + :set Link "https://rsc.eworm.de/#donate"; } $SendNotification2 ({ origin=$0; \ @@ -873,12 +1201,11 @@ # lock script against multiple invocation :set ScriptLock do={ :local Script [ :tostr $1 ]; - :local DoReturn $2; - :local WaitMax ([ :tonum $3 ] * 10); + :local WaitMax ([ :tonum $3 ] * 10); - :global GetRandom20CharHex; + :global GetRandom20CharAlNum; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ScriptLockOrder; :if ([ :typeof $ScriptLockOrder ] = "nothing") do={ @@ -964,20 +1291,22 @@ } :if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ - $LogPrintExit2 error $0 ("A script named '" . $Script . "' does not exist!") true; + $LogPrint error $0 ("A script named '" . $Script . "' does not exist!"); + :error false; } :if ([ $JobCount $Script ] = 0) do={ - $LogPrintExit2 error $0 ("No script '" . $Script . "' is running!") true; + $LogPrint error $0 ("No script '" . $Script . "' is running!"); + :error false; } :if ([ $TicketCount $Script ] >= [ $JobCount $Script ]) do={ - $LogPrintExit2 error $0 ("More tickets than running scripts '" . $Script . "', resetting!") false; + $LogPrint error $0 ("More tickets than running scripts '" . $Script . "', resetting!"); :set ($ScriptLockOrder->$Script) ({}); /system/script/job/remove [ find where script=$Script ]; } - :local MyTicket [ $GetRandom20CharHex ]; + :local MyTicket [ $GetRandom20CharAlNum 6 ]; $AddTicket $Script $MyTicket; :local WaitCount 0; @@ -989,13 +1318,13 @@ :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ $RemoveTicket $Script $MyTicket; $CleanupTickets $Script; - :return false; + :return true; } $RemoveTicket $Script $MyTicket; - $LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ - " and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; - :return true; + $LogPrint info $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 @@ -1020,9 +1349,17 @@ # 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"; @@ -1030,30 +1367,45 @@ "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"; - "up-arrow"="\E2\AC\86"; + "speech-balloon"="\F0\9F\92\AC"; + "star"="\E2\AD\90"; "warning-sign"="\E2\9A\A0"; "white-heavy-check-mark"="\E2\9C\85" } - :return ($Symbols->$1); + :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 ""; + :return [ $IfThenElse ([ :len $2 ] > 0) ([ :tostr $2 ] . " ") "" ]; } :local Return ""; :foreach Symbol in=[ :toarray $1 ] do={ @@ -1062,6 +1414,16 @@ :return ($Return . " "); } +# convert line endings, UNIX -> DOS +:set Unix2Dos do={ + :local Input [ :tostr $1 ]; + + :global CharacterReplace; + + :return [ $CharacterReplace [ $CharacterReplace $Input \ + ("\n") ("\r\n") ] ("\r\r\n") ("\r\n") ]; +} + # url encoding :set UrlEncode do={ :local Input [ :tostr $1 ]; @@ -1071,7 +1433,7 @@ } :local Return ""; - :local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~"); + :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" }; @@ -1109,8 +1471,10 @@ :global CharacterReplace; - :set Input [ $CharacterReplace [ $CharacterReplace [ $CharacterReplace $Input \ - "." "," ] "beta" ",beta," ] "rc" ",rc," ]; + :set Input [ $CharacterReplace $Input "." "," ]; + :foreach I in={ "alpha"; "beta"; "rc" } do={ + :set Input [ $CharacterReplace $Input $I ("," . $I . ",") ]; + } :foreach Value in=([ :toarray $Input ], 0) do={ :local Num [ :tonum $Value ]; @@ -1119,7 +1483,8 @@ :set Return ($Return + 0xff00); :set Multi ($Multi / 0x100); } else={ - :if ($Value = "beta") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "alpha") do={ :set Return ($Return + 0x3f00); } + :if ($Value = "beta") do={ :set Return ($Return + 0x5f00); } :if ($Value = "rc") do={ :set Return ($Return + 0x7f00); } } } @@ -1150,18 +1515,21 @@ # wait for file to be available :set WaitForFile do={ - :local FileName [ :tostr $1 ]; + :local FileName [ :tostr $1 ]; + :local WaitTime [ :totime $2 ]; :global CleanFilePath; + :global EitherOr; :set FileName [ $CleanFilePath $FileName ]; - :local I 0; + :local I 1; + :local Delay ([ :totime [ $EitherOr $WaitTime 2s ] ] / 20); :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I > 20) do={ + :if ($I >= 20) do={ :return false; } - :delay 100ms; + :delay $Delay; :set I ($I + 1); } :return true; @@ -1194,15 +1562,17 @@ :do { /system/script/run $Script; } on-error={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; + $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run."); } } else={ - $LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; + $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); } } -# check for required RouterOS version -$RequiredRouterOS $0 "7.1" true; +# 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.rsc index 43cc5cc..f8c767b 100644 --- a/global-wait +++ b/global-wait.rsc @@ -1,11 +1,12 @@ #!rsc by RouterOS # RouterOS script: global-wait -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # +# requires RouterOS, version=7.12 +# # wait for global-functions to finish # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md -:local 0 "global-wait"; :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } diff --git a/gps-track b/gps-track deleted file mode 100644 index 56a26c5..0000000 --- a/gps-track +++ /dev/null @@ -1,34 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: gps-track -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# track gps data by sending json data to http server -# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md - -:local 0 "gps-track"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global GpsTrackUrl; -:global Identity; - -:global LogPrintExit2; - -:local CoordinateFormat [ /system/gps/get coordinate-format ]; -:local Gps [ /system/gps/monitor once as-value ]; - -:if ($Gps->"valid" = true) do={ - /tool/fetch check-certificate=yes-without-crl $GpsTrackUrl output=none \ - http-method=post http-header-field="Content-Type: application/json" \ - http-data=("{" . \ - "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ - "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ - "\"identity\":\"" . $Identity . "\"" . \ - "}") as-value; - $LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \ - "lat: " . ($Gps->"latitude") . " " . \ - "lon: " . ($Gps->"longitude")) false; -} else={ - $LogPrintExit2 debug $0 ("GPS data not valid.") false; -} diff --git a/gps-track.rsc b/gps-track.rsc new file mode 100644 index 0000000..1aeab84 --- /dev/null +++ b/gps-track.rsc @@ -0,0 +1,50 @@ +#!rsc by RouterOS +# RouterOS script: gps-track +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# track gps data by sending json data to http server +# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global GpsTrackUrl; + :global Identity; + + :global LogPrint; + :global ScriptLock; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 $GpsTrackUrl output=none \ + http-method=post http-header-field=({ "Content-Type: application/json" }) \ + http-data=("{" . \ + "\"lat\":\"" . ($Gps->"latitude") . "\"," . \ + "\"lon\":\"" . ($Gps->"longitude") . "\"," . \ + "\"identity\":\"" . $Identity . "\"" . \ + "}") as-value; + $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={ } diff --git a/hotspot-to-wpa b/hotspot-to-wpa deleted file mode 100644 index add2893..0000000 --- a/hotspot-to-wpa +++ /dev/null @@ -1,72 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa -# Copyright (c) 2019-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# add private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; - -:local MacAddress $"mac-address"; -:local UserName $username; -:local Date [ /system/clock/get date ]; -:local UserVal [ /ip/hotspot/user/get [ find where name=$UserName ] ]; -:local UserInfo [ $ParseKeyValueStore ($UserVal->"comment") ]; -:local Hotspot [ /ip/hotspot/host/get [ find where mac-address=$MacAddress authorized ] server ]; - -:if ([ :len [ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ] ] = 0) do={ - /caps-man/access-list/add comment="--- hotspot-to-wpa above ---" disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- hotspot-to-wpa above ---'.") false; -} -:local PlaceBefore ([ /caps-man/access-list/find where comment="--- hotspot-to-wpa above ---" disabled ]->0); - -:if ([ :len [ /caps-man/access-list/find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ] ] = 0) do={ - /caps-man/access-list/add comment=("hotspot-to-wpa template " . $Hotspot) disabled=yes place-before=$PlaceBefore; - $LogPrintExit2 warning $0 ("Added template in access-list for hotspot '" . $Hotspot . "'.") false; -} -:local Template [ /caps-man/access-list/get ([ find where \ - comment=("hotspot-to-wpa template " . $Hotspot) disabled ]->0) ]; - -:if ($Template->"action" = "reject") do={ - $LogPrintExit2 info $0 ("Ignoring login for hotspot '" . $Hotspot . "'.") true; -} - -# allow login page to load -:delay 1s; - -$LogPrintExit2 info $0 ("Adding/updating access-list entry for mac address " . $MacAddress . \ - " (user " . $UserName . ").") false; -/caps-man/access-list/remove [ find where mac-address=$MacAddress comment~"^hotspot-to-wpa: " ]; -/caps-man/access-list/add comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) \ - mac-address=$MacAddress private-passphrase=($UserVal->"password") ssid-regexp="-wpa\$" place-before=$PlaceBefore; - -:local Entry [ /caps-man/access-list/find where mac-address=$MacAddress \ - comment=("hotspot-to-wpa: " . $UserName . ", " . $MacAddress . ", " . $Date) ]; -:local PrivatePassphrase [ $EitherOr ($UserInfo->"private-passphrase") ($Template->"private-passphrase") ]; -:if ([ :len $PrivatePassphrase ] > 0) do={ - :if ($PrivatePassphrase = "ignore") do={ - /caps-man/access-list/set $Entry !private-passphrase; - } else={ - /caps-man/access-list/set $Entry private-passphrase=$PrivatePassphrase; - } -} -:local SsidRegexp [ $EitherOr ($UserInfo->"ssid-regexp") ($Template->"ssid-regexp") ]; -:if ([ :len $SsidRegexp ] > 0) do={ - /caps-man/access-list/set $Entry ssid-regexp=$SsidRegexp; -} -:local VlanId [ $EitherOr ($UserInfo->"vlan-id") ($Template->"vlan-id") ]; -:if ([ :len $VlanId ] > 0) do={ - /caps-man/access-list/set $Entry vlan-id=$VlanId; -} -:local VlanMode [ $EitherOr ($UserInfo->"vlan-mode") ($Template->"vlan-mode") ]; -:if ([ :len $VlanMode] > 0) do={ - /caps-man/access-list/set $Entry vlan-mode=$VlanMode; -} diff --git a/hotspot-to-wpa-cleanup b/hotspot-to-wpa-cleanup deleted file mode 100644 index 26610ae..0000000 --- a/hotspot-to-wpa-cleanup +++ /dev/null @@ -1,51 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: hotspot-to-wpa-cleanup -# Copyright (c) 2021-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: lease-script, order=80 -# -# manage and clean up private WPA passphrase after hotspot login -# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md - -:local 0 "hotspot-to-wpa-cleanup"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -:global ScriptLock; - -$ScriptLock $0 false 10; - -:foreach Client in=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={ - :local ClientVal [ /caps-man/registration-table/get $Client ]; - :local Lease [ /ip/dhcp-server/lease/find where server~"wpa" dynamic \ - mac-address=($ClientVal->"mac-address") ]; - :if ([ :len $Lease ] > 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " connected to WPA, making lease static.") false; - /ip/dhcp-server/lease/make-static $Lease; - /ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease; - } -} - -:foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" and \ - !(comment~[ /system/clock/get date ]) ] do={ - :local ClientVal [ /caps-man/access-list/get $Client ]; - :if ([ :len [ /ip/dhcp-server/lease/find where server~"wpa" !dynamic \ - mac-address=($ClientVal->"mac-address") ] ] = 0) do={ - $LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ - " did not connect to WPA, removing from access list.") false; - /caps-man/access-list/remove $Client; - } -} - -:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status=waiting \ - last-seen>4w comment~"^hotspot-to-wpa:" ] do={ - :local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; - $LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ - " was not seen for long time, removing.") false; - /caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ - mac-address=($LeaseVal->"mac-address") ]; - /ip/dhcp-server/lease/remove $Lease; -} diff --git a/hotspot-to-wpa-cleanup.capsman.rsc b/hotspot-to-wpa-cleanup.capsman.rsc new file mode 100644 index 0000000..0540ad5 --- /dev/null +++ b/hotspot-to-wpa-cleanup.capsman.rsc @@ -0,0 +1,74 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup.capsman +# Copyright (c) 2021-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# requires RouterOS, version=7.12 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :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 ]) ] 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={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout 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={ } diff --git a/hotspot-to-wpa-cleanup.template.rsc b/hotspot-to-wpa-cleanup.template.rsc new file mode 100644 index 0000000..6f3b3e1 --- /dev/null +++ b/hotspot-to-wpa-cleanup.template.rsc @@ -0,0 +1,81 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup%TEMPL% +# Copyright (c) 2021-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# requires RouterOS, version=7.12 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :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 ]) ] 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={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout 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={ } diff --git a/hotspot-to-wpa-cleanup.wifi.rsc b/hotspot-to-wpa-cleanup.wifi.rsc new file mode 100644 index 0000000..9c79628 --- /dev/null +++ b/hotspot-to-wpa-cleanup.wifi.rsc @@ -0,0 +1,74 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa-cleanup.wifi +# Copyright (c) 2021-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: lease-script, order=80 +# requires RouterOS, version=7.12 +# +# manage and clean up private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :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 ]) ] 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={ + :foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ + server=$Server last-seen>$Timeout 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={ } diff --git a/hotspot-to-wpa.capsman.rsc b/hotspot-to-wpa.capsman.rsc new file mode 100644 index 0000000..37c8464 --- /dev/null +++ b/hotspot-to-wpa.capsman.rsc @@ -0,0 +1,98 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.capsman +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :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 . "'."); + :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={ } diff --git a/hotspot-to-wpa.template.rsc b/hotspot-to-wpa.template.rsc new file mode 100644 index 0000000..cbce42a --- /dev/null +++ b/hotspot-to-wpa.template.rsc @@ -0,0 +1,118 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa%TEMPL% +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/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; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :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 . "'."); + :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={ } diff --git a/hotspot-to-wpa.wifi.rsc b/hotspot-to-wpa.wifi.rsc new file mode 100644 index 0000000..86aeed7 --- /dev/null +++ b/hotspot-to-wpa.wifi.rsc @@ -0,0 +1,95 @@ +#!rsc by RouterOS +# RouterOS script: hotspot-to-wpa.wifi +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# add private WPA passphrase after hotspot login +# https://git.eworm.de/cgit/routeros-scripts/about/doc/hotspot-to-wpa.md +# +# !! Do not edit this file, it is generated from template! + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :local MacAddress $"mac-address"; + :local UserName $username; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :if ([ :typeof $MacAddress ] = "nothing" || [ :typeof $UserName ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from hotspot on login."); + :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 . "'."); + :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={ } diff --git a/ip-addr-bridge b/ip-addr-bridge.rsc index 218eb2e..758cd46 100644 --- a/ip-addr-bridge +++ b/ip-addr-bridge.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: ip-addr-bridge -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable or disable ip addresses based on bridge port state diff --git a/ipsec-to-dns b/ipsec-to-dns deleted file mode 100644 index c6cfdc4..0000000 --- a/ipsec-to-dns +++ /dev/null @@ -1,68 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ipsec-to-dns -# Copyright (c) 2021-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# and add/remove/update DNS entries from IPSec mode-config -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md - -:local 0 "ipsec-to-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Domain; -:global HostNameInZone; -:global Identity; -:global PrefixInZone; - -:global CharacterReplace; -:global LogPrintExit2; -:global IfThenElse; - -:local Zone \ - ([ $IfThenElse ($PrefixInZone = true) "ipsec." ] . \ - [ $IfThenElse ($HostNameInZone = true) ($Identity . ".") ] . $Domain); -:local Ttl 5m; -:local CommentPrefix ("managed by " . $0 . " for "); -:local CommentString ("--- " . $0 . " above ---"); - -:if ([ :len [ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ] ] = 0) do={ - /ip/dns/static/add comment=$CommentString name=- type=NXDOMAIN disabled=yes; - $LogPrintExit2 warning $0 ("Added disabled static dns record with comment '" . $CommentString . "'.") false; -} -:local PlaceBefore ([ /ip/dns/static/find where comment=$CommentString name=- type=NXDOMAIN disabled ]->0); - -:foreach DnsRecord in=[ /ip/dns/static/find where comment ~ $CommentPrefix ] do={ - :local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; - :local PeerId [ $CharacterReplace ($DnsRecordVal->"comment") $CommentPrefix "" ]; - :if ([ :len [ /ip/ipsec/active-peers/find where id=$PeerId dynamic-address=($DnsRecordVal->"address") ] ] > 0) do={ - $LogPrintExit2 debug $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting DNS entry.") false; - } else={ - :local Found false; - $LogPrintExit2 info $0 ("Peer " . $PeerId . " (" . $DnsRecordVal->"name" . ") has gone, deleting DNS entry.") false; - /ip/dns/static/remove $DnsRecord; - } -} - -:foreach Peer in=[ /ip/ipsec/active-peers/find where !(dynamic-address=[]) ] do={ - :local PeerVal [ /ip/ipsec/active-peers/get $Peer ]; - :local Comment ($CommentPrefix . $PeerVal->"id"); -:put ($PeerVal->"id"); - :local HostName [ :pick ($PeerVal->"id") 0 [ :find ($PeerVal->"id" . ".") "." ] ]; -:put $HostName; - - :local Fqdn ($HostName . "." . $Zone); - :local DnsRecord [ /ip/dns/static/find where name=$Fqdn ]; - :if ([ :len $DnsRecord ] > 0) do={ - :local DnsIp [ /ip/dns/static/get $DnsRecord address ]; - :if ($DnsIp = $PeerVal->"dynamic-address") do={ - $LogPrintExit2 debug $0 ("DNS entry for " . $Fqdn . " does not need updating.") false; - } else={ - $LogPrintExit2 info $0 ("Replacing DNS entry for " . $Fqdn . ", new address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/set name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment $DnsRecord; - } - } else={ - $LogPrintExit2 info $0 ("Adding new DNS entry for " . $Fqdn . ", address is " . $PeerVal->"dynamic-address" . ".") false; - /ip/dns/static/add name=$Fqdn address=($PeerVal->"dynamic-address") ttl=$Ttl comment=$Comment place-before=$PlaceBefore; - } -} diff --git a/ipsec-to-dns.rsc b/ipsec-to-dns.rsc new file mode 100644 index 0000000..dd40ca2 --- /dev/null +++ b/ipsec-to-dns.rsc @@ -0,0 +1,79 @@ +#!rsc by RouterOS +# RouterOS script: ipsec-to-dns +# Copyright (c) 2021-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# and add/remove/update DNS entries from IPSec mode-config +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipsec-to-dns.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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={ } diff --git a/ipv6-update b/ipv6-update deleted file mode 100644 index b81a0ec..0000000 --- a/ipv6-update +++ /dev/null @@ -1,62 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ipv6-update -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# update firewall and dns settings on IPv6 prefix change -# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md - -:local 0 "ipv6-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:local PdPrefix $"pd-prefix"; - -:global LogPrintExit2; -:global ParseKeyValueStore; - -:if ([ :typeof $PdPrefix ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ipv6 dhcp-client.") true; -} - -:local Pool [ /ipv6/pool/get [ find where prefix=$PdPrefix ] name ]; -:if ([ :len [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ] ] = 0) do={ - /ipv6/firewall/address-list/add list=("ipv6-pool-" . $Pool) address=:: comment=("ipv6-pool-" . $Pool); - $LogPrintExit2 warning $0 ("Added ipv6 address list entry for ipv6-pool-" . $Pool) false; -} -:local AddrList [ /ipv6/firewall/address-list/find where comment=("ipv6-pool-" . $Pool) ]; -:local OldPrefix [ /ipv6/firewall/address-list/get ($AddrList->0) address ]; - -:if ($OldPrefix != $PdPrefix) do={ - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $PdPrefix) false; - /ipv6/firewall/address-list/set address=$PdPrefix $AddrList; - - # give the interfaces a moment to receive their addresses - :delay 2s; - - :foreach ListEntry in=[ /ipv6/firewall/address-list/find where comment~("^ipv6-pool-" . $Pool . ",") ] do={ - :local ListEntryVal [ /ipv6/firewall/address-list/get $ListEntry ]; - :local Comment [ $ParseKeyValueStore ($ListEntryVal->"comment") ]; - - :local Address [ /ipv6/address/find where from-pool=$Pool interface=($Comment->"interface") ]; - :if ([ :len $Address ] = 1) do={ - :set Address [ /ipv6/address/get $Address address ]; - $LogPrintExit2 info $0 ("Updating IPv6 address list with new IPv6 prefix " . $Address . \ - " from interface " . ($Comment->"interface")) false; - /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" ] ] ] & ffff:ffff:ffff:ffff::); - :local Address ($Prefix | ([ :toip6 ($RecordVal->"address") ] & ::ffff:ffff:ffff:ffff)); - - $LogPrintExit2 info $0 ("Updating DNS record for " . ($RecordVal->"name") . \ - ($RecordVal->"regexp") . " to " . $Address) false; - /ip/dns/static/set address=$Address $Record; - } -} diff --git a/ipv6-update.rsc b/ipv6-update.rsc new file mode 100644 index 0000000..65bb959 --- /dev/null +++ b/ipv6-update.rsc @@ -0,0 +1,87 @@ +#!rsc by RouterOS +# RouterOS script: ipv6-update +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# update firewall and dns settings on IPv6 prefix change +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ipv6-update.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :local PdPrefix $"pd-prefix"; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :if ([ :typeof $PdPrefix ] = "nothing") do={ + $LogPrint error $ScriptName ("This script is supposed to run from ipv6 dhcp-client."); + :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); + $LogPrint warning $ScriptName ("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={ + $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={ } diff --git a/lease-script b/lease-script deleted file mode 100644 index cc1b6e5..0000000 --- a/lease-script +++ /dev/null @@ -1,54 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: lease-script -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# run scripts on DHCP lease -# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md - -:local 0 "lease-script"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global IfThenElse; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -:if ([ :typeof $leaseActIP ] = "nothing" || \ - [ :typeof $leaseActMAC ] = "nothing" || \ - [ :typeof $leaseServerName ] = "nothing" || \ - [ :typeof $leaseBound ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ip dhcp-server.") true; -} - -$LogPrintExit2 debug $0 ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ - "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC) false; - -$ScriptLock $0 false 10; - -:if ([ :len [ /system/script/job/find where script=$0 ] ] > 1) do={ - $LogPrintExit2 debug $0 ("More invocations are waiting, exiting early.") true; -} - -:local RunOrder ({}); - -:foreach Script in=[ /system/script/find where source~("\n# provides: lease-script, ") ] do={ - :local Name [ /system/script/get $Script name ]; - :local Store [ /system/script/get $Script source ]; - - :set Store [ :pick $Store ([ :find $Store "\n# provides: lease-script, " ] + 27) [ :len $Store ] ]; - :set Store [ :pick $Store 0 [ :find $Store "\n" ] ]; - :set Store [ $ParseKeyValueStore $Store ]; - - :set ($RunOrder->($Store->"order")) $Name; -} - -:foreach Order,Script in=$RunOrder do={ - :do { - $LogPrintExit2 debug $0 ("Running script with order " . $Order . ": " . $Script) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $Script . "' failed!") false; - } -} diff --git a/lease-script.rsc b/lease-script.rsc new file mode 100644 index 0000000..8e1e8f6 --- /dev/null +++ b/lease-script.rsc @@ -0,0 +1,59 @@ +#!rsc by RouterOS +# RouterOS script: lease-script +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# run scripts on DHCP lease +# https://git.eworm.de/cgit/routeros-scripts/about/doc/lease-script.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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."); + :error false; + } + + $LogPrint debug $ScriptName ("DHCP Server " . $leaseServerName . " " . [ $IfThenElse ($leaseBound = 0) \ + "de" "" ] . "assigned lease " . $leaseActIP . " to " . $leaseActMAC); + + :if ([ $ScriptLock $ScriptName 10 ] = false) do={ + :error false; + } + + :if ([ :len [ /system/script/job/find where script=$ScriptName ] ] > 1) do={ + $LogPrint debug $ScriptName ("More invocations are waiting, exiting early."); + :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={ } diff --git a/leds-day-mode b/leds-day-mode.rsc index 78e1fae..b7c6b5b 100644 --- a/leds-day-mode +++ b/leds-day-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-day-mode -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # enable LEDs diff --git a/leds-night-mode b/leds-night-mode.rsc index 112f9a1..fb7c7a2 100644 --- a/leds-night-mode +++ b/leds-night-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-night-mode -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # disable LEDs diff --git a/leds-toggle-mode b/leds-toggle-mode.rsc index 225ceb2..136c9d1 100644 --- a/leds-toggle-mode +++ b/leds-toggle-mode.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: leds-toggle-mode -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # toggle LEDs mode diff --git a/log-forward b/log-forward deleted file mode 100644 index 6ccad4f..0000000 --- a/log-forward +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: log-forward -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# forward log messages via notification -# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md - -:local 0 "log-forward"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; -:global LogForwardFilter; -:global LogForwardFilterMessage; -:global LogForwardInclude; -:global LogForwardIncludeMessage; -:global LogForwardLast; -:global LogForwardRateLimit; -:global NotificationsWithSymbols; - -:global EscapeForRegEx; -:global HexToNum; -:global IfThenElse; -:global LogPrintExit2; -:global QuotedPrintable; -:global ScriptLock; -:global SendNotification2; -:global SymbolByUnicodeName; -:global SymbolForNotification; - -$ScriptLock $0; - -:if ([ :typeof $LogForwardRateLimit ] = "nothing") do={ - :set LogForwardRateLimit 0; -} - -:if ($LogForwardRateLimit > 30) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - $LogPrintExit2 info $0 ("Rate limit in action, not forwarding logs, if any!") true; -} - -:local Count 0; -:local Duplicates false; -:local Last [ $IfThenElse ([ :len $LogForwardLast ] > 0) [ $HexToNum $LogForwardLast ] -1 ]; -:local Messages ""; -:local Warning false; -:local MessageVal; -:local MessageDups ({}); - -:local LogForwardFilterLogForwarding ("^Error sending e-mail <(" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "memo" ] . "Log Forwarding") ] ] . "|" . \ - [ $EscapeForRegEx [ $QuotedPrintable ("[" . $Identity . "] " . \ - [ $SymbolForNotification "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); -:foreach Message in=[ /log/find where (!(message="") and !(message~$LogForwardFilterLogForwarding) and \ - !(topics~$LogForwardFilter) and !(message~$LogForwardFilterMessage)) or \ - topics~$LogForwardInclude or message~$LogForwardIncludeMessage ] do={ - :set MessageVal [ /log/get $Message ]; - - :if ($Last < [ $HexToNum ($MessageVal->".id") ]) do={ - :local DupCount ($MessageDups->($MessageVal->"message")); - :if ($MessageVal->"topics" ~ "(emergency|alert|critical|error|warning)") do={ - :set Warning true; - } - :if ($DupCount < 3) do={ - :set Messages ($Messages . "\n" . [ $IfThenElse ($NotificationsWithSymbols = true) (" \E2\97\8F ") ] . \ - $MessageVal->"time" . " " . [ :tostr ($MessageVal->"topics") ] . " " . $MessageVal->"message"); - } else={ - :set Duplicates true; - } - :set ($MessageDups->($MessageVal->"message")) ($DupCount + 1); - :set Count ($Count + 1); - } -} - -:if ($Count > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit + 10); - - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification [ $IfThenElse ($Warning = true) "warning-sign" "memo" ] ] . \ - "Log Forwarding"); \ - message=("The log on " . $Identity . " contains " . [ $IfThenElse ($Count = 1) "this message" \ - ("these " . $Count . " messages") ] . " after " . [ /system/resource/get uptime ] . " uptime." . \ - [ $IfThenElse ($Duplicates = true) (" Multi-repeated messages have been skipped.") ] . \ - [ $IfThenElse ($LogForwardRateLimit > 30) ("\nRate limit in action, delaying forwarding.") ] . \ - "\n" . $Messages) }); - - :set LogForwardLast ($MessageVal->".id"); -} else={ - :if ($LogForwardRateLimit > 0) do={ - :set LogForwardRateLimit ($LogForwardRateLimit - 1); - } -} diff --git a/log-forward.rsc b/log-forward.rsc new file mode 100644 index 0000000..a919d8f --- /dev/null +++ b/log-forward.rsc @@ -0,0 +1,102 @@ +#!rsc by RouterOS +# RouterOS script: log-forward +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# forward log messages via notification +# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :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!"); + :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 ({}); + + :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) }); + + :set LogForwardLast ($MessageVal->".id"); + } else={ + :set LogForwardRateLimit [ $MAX 0 ($LogForwardRateLimit - 1) ]; + } +} on-error={ } Binary files differBinary files differ@@ -1,23 +1,29 @@ <?xml version="1.0" encoding="UTF-8"?> -<svg width="96" height="96" version="1.1" viewBox="0 0 25.4 25.4" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - </cc:Work> - </rdf:RDF> - </metadata> - <path d="m23.177 23.177c-2.9635 2.9635-17.991 2.9635-20.955 0-2.9635-2.9635-2.9635-17.991 0-20.955 2.9635-2.9635 17.991-2.9635 20.955 0 2.9635 2.9635 2.9635 17.991 0 20.955z" fill="#fff"/> - <g stroke-width=".26458px" aria-label="#!rsc"> - <path d="m7.4832 16.646v-1.0239h-0.54606l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.97511l0.16577-1.2774h-1.2774l-0.16577 1.2774h-0.70208v1.0239h0.56556l-0.24378 1.8722h-0.68257v1.0239h0.54606l-0.18527 1.3944h1.2774l0.18527-1.3944h0.97511l-0.18527 1.3944h1.2774l0.18527-1.3944h0.70208v-1.0239h-0.56556l0.24378-1.8722zm-2.2037 1.8722h-0.97511l0.24378-1.8722h0.97511z"/> - <path d="m9.6187 14.179h-1.6382l0.19502 4.271h1.2481zm-0.81909 5.1583c-0.48755 0-0.8776 0.39979-0.8776 0.8776 0 0.48755 0.39004 0.88735 0.8776 0.88735 0.4973 0 0.88735-0.39979 0.88735-0.88735 0-0.4778-0.39004-0.8776-0.88735-0.8776z"/> - <path d="m13.373 15.612c-0.59482 0-1.1019 0.42905-1.3359 1.1506l-0.13652-1.0044h-1.3359v5.1778h1.5407v-2.6035c0.17552-0.77033 0.4388-1.2286 1.0726-1.2286 0.16577 0 0.30228 0.02925 0.46805 0.06826l0.24378-1.4919c-0.17552-0.04875-0.32178-0.06826-0.51681-0.06826z"/> - <path d="m16.181 15.592c-1.3066 0-2.116 0.69233-2.116 1.5797 0 0.79959 0.50706 1.3261 1.5309 1.6187 0.9361 0.26328 1.0921 0.37054 1.0921 0.72158 0 0.31203-0.28278 0.48755-0.75083 0.48755-0.50706 0-0.98486-0.20477-1.3749-0.50706l-0.75083 0.83859c0.50706 0.4583 1.2676 0.77033 2.1647 0.77033 1.2871 0 2.3012-0.63382 2.3012-1.7064 0-0.92635-0.57531-1.3554-1.5992-1.6479-0.92635-0.27303-1.0629-0.39004-1.0629-0.66307 0-0.23402 0.20477-0.39004 0.62407-0.39004 0.44855 0 0.8776 0.14627 1.2774 0.39979l0.56556-0.86784c-0.4778-0.39004-1.1506-0.63382-1.9015-0.63382z"/> - <path d="m21.281 15.592c-1.5504 0-2.5353 1.1506-2.5353 2.7986 0 1.6382 0.97511 2.7108 2.5645 2.7108 0.71183 0 1.2676-0.23403 1.7454-0.61432l-0.67282-0.9556c-0.37054 0.23403-0.62407 0.35104-0.99461 0.35104-0.61432 0-1.0239-0.35104-1.0239-1.5017 0-1.1604 0.38029-1.6089 1.0434-1.6089 0.35104 0 0.65332 0.11701 0.98486 0.37054l0.66307-0.9166c-0.4973-0.4193-1.0531-0.63382-1.7747-0.63382z"/> - </g> - <g transform="matrix(2 0 0 2 -.41134 3.175)" fill="#676867" fill-rule="evenodd" stroke-width=".13229"> - <path d="m4.9596-1.0196c0.40797 2.8312 1.9272 4.5499 5.0239 4.691-2.918 1.1164-5.9253-1.5076-5.0239-4.691"/> - <path d="m3.3407-0.52096c0.034969-0.00777 0.038854 0.015542 0.041445 0.041445 0.098431 1.8054 0.85998 3.1744 1.8689 4.1108 1.0089 0.93639 2.3636 1.6941 4.274 1.6604-3.5772 1.4247-7.337-1.9984-6.1856-5.8126"/> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg id="svg" width="96" height="96" version="1.1" viewBox="0 0 25.4 25.4" xmlns="http://www.w3.org/2000/svg"> + <defs id="defs"> + <radialGradient id="radGradDark" cx="7.5006" cy="9.4015" r="9.7854" gradientTransform="matrix(1.6107 1.0797 -.58681 .87543 .93614 -7.022)" gradientUnits="userSpaceOnUse"> + <stop id="dark-1" stop-color="#222" offset="0"/> + <stop id="dark-2" stop-color="#444" offset="1"/> + </radialGradient> + <radialGradient id="radGradRed" cx="14.501" cy="10.029" r="2.6711" gradientTransform="matrix(1.3827 .62837 -.44627 .98203 -1.0744 -8.9965)" gradientUnits="userSpaceOnUse"> + <stop id="red-1" stop-color="#a00" offset="0"/> + <stop id="red-2" stop-color="#c22" offset="1"/> + </radialGradient> + </defs> + <g id="layer1"> + <rect id="background" x="4.5766e-15" width="25.4" height="25.4" ry="5.1528" fill="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="13.229"/> + <path id="hexagon" d="m17.758 12.437-1.3326 0.77071a0.94166 0.94328 0 0 1-0.94166 0l-1.3326-0.77071a0.94166 0.94328 0 0 1-0.47083-0.8169v-1.5414a0.94166 0.94328 0 0 1 0.47083-0.8169l1.3326-0.77071a0.94166 0.94328 0 0 1 0.94166 0l1.3326 0.77071a0.94166 0.94328 0 0 1 0.47083 0.8169v1.5414a0.94166 0.94328 0 0 1-0.47083 0.8169z" fill="url(#radGradRed)" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width=".79375"/> + <g id="text" fill="url(#radGradDark)" stroke="#000" stroke-width=".1"> + <g id="shebang" aria-label="#!"> + <path id="path904" d="m13.767 4.8761v-1.6506h-0.88032l0.26724-2.0593h-2.0593l-0.26724 2.0593h-1.572l0.26724-2.0593h-2.0593l-0.26724 2.0593h-1.1318v1.6506h0.91175l-0.393 3.0182h-1.1004v1.6506h0.88031l-0.29868 2.2479h2.0593l0.29868-2.2479h1.572l-0.29868 2.2479h2.0593l0.29868-2.2479h1.1318v-1.6506h-0.91175l0.393-3.0182zm-3.5527 3.0182h-1.572l0.393-3.0182h1.572z"/> + <path id="path906" d="m17.209 0.89898h-2.6409l0.3144 6.8853s0.66885-0.28785 1.0123-0.28746c0.33937 3.865e-4 0.99985 0.28746 0.99985 0.28746z"/> + </g> + <g id="rsc" aria-label="rsc"> + <path id="path910" d="m7.5809 12.875c-0.92632 0-1.716 0.66817-2.0804 1.7919l-0.2126-1.5641h-2.0804v8.0636h2.3993v-4.0546c0.27334-1.1997 0.68335-1.9134 1.6704-1.9134 0.25816 0 0.47075 0.04556 0.72891 0.1063l0.37964-2.3234c-0.27334-0.075928-0.50112-0.1063-0.80484-0.1063z"/> + <path id="path912" d="m11.954 12.845c-2.0349 0-3.2953 1.0782-3.2953 2.4601 0 1.2452 0.78965 2.0652 2.3841 2.5208 1.4578 0.41001 1.7008 0.57705 1.7008 1.1237 0 0.48594-0.44038 0.75928-1.1693 0.75928-0.78965 0-1.5337-0.3189-2.1412-0.78965l-1.1693 1.306c0.78965 0.71372 1.9741 1.1997 3.3712 1.1997 2.0045 0 3.5838-0.98706 3.5838-2.6575 0-1.4426-0.89595-2.1108-2.4904-2.5664-1.4426-0.4252-1.6552-0.60742-1.6552-1.0326 0-0.36445 0.3189-0.60742 0.97188-0.60742 0.69854 0 1.3667 0.22778 1.9893 0.62261l0.88076-1.3515c-0.7441-0.60742-1.7919-0.98706-2.9612-0.98706z"/> + <path id="path914" d="m19.896 12.845c-2.4145 0-3.9483 1.7919-3.9483 4.3583 0 2.5512 1.5186 4.2216 3.9938 4.2216 1.1085 0 1.9741-0.36446 2.7182-0.95669l-1.0478-1.4882c-0.57705 0.36445-0.97188 0.54668-1.5489 0.54668-0.95669 0-1.5945-0.54668-1.5945-2.3386 0-1.8071 0.59224-2.5056 1.6249-2.5056 0.54668 0 1.0174 0.18223 1.5337 0.57705l1.0326-1.4274c-0.77446-0.65298-1.64-0.98706-2.7638-0.98706z"/> + </g> + </g> </g> </svg> diff --git a/mod/bridge-port-to b/mod/bridge-port-to.rsc index 3f62e6f..567a762 100644 --- a/mod/bridge-port-to +++ b/mod/bridge-port-to.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-to -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # reset bridge ports to default bridge @@ -12,7 +12,7 @@ :local BridgePortTo [ :tostr $1 ]; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :local InterfaceReEnable ({}); @@ -24,21 +24,22 @@ :if ($BridgeDefault = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + $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={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + $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={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ", disabling dhcp client.") false; + $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; @@ -50,16 +51,16 @@ } /interface/bridge/port/set disabled=no bridge=$BridgeDefault $BridgePort; } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ - " bridge " . $BridgeDefault . ".") false; + $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $BridgePortTo . \ + " bridge " . $BridgeDefault . "."); } } } } } :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + :delay 5s; + $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } } diff --git a/mod/bridge-port-vlan b/mod/bridge-port-vlan.rsc index 9a6e08a..aee5ef9 100644 --- a/mod/bridge-port-vlan +++ b/mod/bridge-port-vlan.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: mod/bridge-port-vlan -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # manage VLANs on bridge ports @@ -12,7 +12,7 @@ :local ConfigTo [ :tostr $1 ]; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; :global ParseKeyValueStore; :local InterfaceReEnable ({}); @@ -24,13 +24,14 @@ :if ($Vlan = "dhcp-client") do={ :if ([ :len $DHCPClient ] != 1) do={ - $LogPrintExit2 warning $0 ([ $IfThenElse ([ :len $DHCPClient ] = 0) "Missing" "Duplicate" ] . \ - " dhcp client configuration for interface " . $BridgePortVal->"interface" . "!") true; + $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={ - $LogPrintExit2 info $0 ("Disabling bridge port for interface " . $BridgePortVal->"interface" . ", enabling dhcp client.") false; + $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; @@ -41,12 +42,13 @@ :do { :set $Vlan ([ /interface/bridge/vlan/get [ find where comment=$Vlan ] vlan-ids ]->0); } on-error={ - $LogPrintExit2 warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!") true; + $LogPrint warning $0 ("Could not find VLAN '" . $Vlan . "' for interface " . $BridgePortVal->"interface" . "!"); + :return false; } } :if ($BridgePortVal->"disabled" = true || $Vlan != $BridgePortVal->"pvid") do={ - $LogPrintExit2 info $0 ("Enabling bridge port for interface " . $BridgePortVal->"interface" . ", changing to " . $ConfigTo . \ - " vlan " . $Vlan . [ $IfThenElse ($Vlan != $VlanName) (" (" . $VlanName . ")") ] . ", disabling dhcp client.") false; + $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; @@ -58,16 +60,16 @@ } /interface/bridge/port/set disabled=no pvid=$Vlan $BridgePort; } else={ - $LogPrintExit2 debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ - " vlan " . $Vlan . ".") false; + $LogPrint debug $0 ("Interface " . $BridgePortVal->"interface" . " already connected to " . $ConfigTo . \ + " vlan " . $Vlan . "."); } } } } } :if ([ :len $InterfaceReEnable ] > 0) do={ - :delay 2s; - $LogPrintExit2 info $0 ("Re-enabling interfaces...") false; + :delay 5s; + $LogPrint info $0 ("Re-enabling interfaces..."); /interface/ethernet/enable $InterfaceReEnable; } } diff --git a/mod/inspectvar b/mod/inspectvar.rsc index 2629b6e..577abf3 100644 --- a/mod/inspectvar +++ b/mod/inspectvar.rsc @@ -1,7 +1,10 @@ #!rsc by RouterOS # RouterOS script: mod/inspectvar -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# inspect variables +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/inspectvar.md :global InspectVar; :global InspectVarReturn; @@ -36,7 +39,7 @@ :local TypeOf [ :typeof $Input ]; :local Return [ $IndentReturn "type" $TypeOf $Level ]; - + :if ($TypeOf = "array") do={ :foreach Key,Value in=$Input do={ :set $Return ($Return . "\n" . \ diff --git a/mod/ipcalc b/mod/ipcalc.rsc index 14bb1ea..b098b44 100644 --- a/mod/ipcalc +++ b/mod/ipcalc.rsc @@ -1,7 +1,10 @@ #!rsc by RouterOS # RouterOS script: mod/ipcalc -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# ip address calculation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ipcalc.md :global IPCalc; :global IPCalcReturn; @@ -10,18 +13,19 @@ :set IPCalc do={ :local Input [ :tostr $1 ]; + :global FormatLine; :global IPCalcReturn; :global PrettyPrint; :local Values [ $IPCalcReturn $1 ]; $PrettyPrint ( \ - "Address: " . $Values->"address" . "\n" . \ - "Netmask: " . $Values->"netmask" . "\n" . \ - "Network: " . $Values->"network" . "\n" . \ - "HostMin: " . $Values->"hostmin" . "\n" . \ - "HostMax: " . $Values->"hostmax" . "\n" . \ - "Broadcast: " . $Values->"broadcast"); + [ $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") ]); } # calculate and return netmask, network, min host, max host and broadcast diff --git a/mod/notification-email b/mod/notification-email deleted file mode 100644 index 0c07beb..0000000 --- a/mod/notification-email +++ /dev/null @@ -1,133 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mod/notification-email -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md - -:global FlushEmailQueue; -:global NotificationFunctions; -:global SendEMail; -:global SendEMail2; - -# flush e-mail queue -:set FlushEmailQueue do={ - :global EmailQueue; - - :global EitherOr; - :global IsDNSResolving; - :global IsTimeSync; - :global LogPrintExit2; - - :local AllDone true; - :local QueueLen [ :len $EmailQueue ]; - - :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ - $LogPrintExit2 debug $0 ("Sending mail in currently in progress, not flushing.") false; - :return false; - } - - :if ([ $IsTimeSync ] = false) do={ - $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false; - :return false; - } - - :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={ - $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false; - :return false; - } - - :if ([ :len [ /system/scheduler/find where name=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false; - } - - /system/scheduler/set interval=($QueueLen . "m") [ find where name=$0 ]; - - :foreach Id,Message in=$EmailQueue do={ - :if ([ :typeof $Message ] = "array" ) do={ - :local Attach [ $EitherOr ($Message->"attach") "" ]; - :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } - /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \ - body=($Message->"body") file=$Attach; - :local Wait true; - :do { - :delay 1s; - :local Status [ /tool/e-mail/get last-status ]; - :if ($Status = "succeeded") do={ - :set ($EmailQueue->$Id); - :set Wait false; - :if (($Message->"remove-attach") = true) do={ - :foreach File in=[ :toarray $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 [ find where name=$0 ]; - :set EmailQueue; - } else={ - /system/scheduler/set interval=1m [ find where name=$0 ]; - } -} - -# send notification via e-mail - expects one array argument -:set ($NotificationFunctions->"email") do={ - :local Notification $1; - - :global Identity; - :global EmailGeneralTo; - :global EmailGeneralToOverride; - :global EmailGeneralCc; - :global EmailGeneralCcOverride; - :global EmailQueue; - - :global EitherOr; - :global IfThenElse; - :global QuotedPrintable; - - :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ]; - :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ]; - - :local EMailSettings [ /tool/e-mail/get ]; - :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={ - :return false; - } - - :if ([ :typeof $EmailQueue ] = "nothing") do={ - :set EmailQueue ({}); - } - :local Signature [ /system/note/get note ]; - :set ($EmailQueue->[ :len $EmailQueue ]) { - to=$To; cc=$Cc; - subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($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 \ - on-event=(":global FlushEmailQueue; \$FlushEmailQueue;"); - } -} - -# send notification via e-mail - expects at least two string arguments -:set SendEMail do={ - :global SendEMail2; - - $SendEMail2 ({ subject=$1; message=$2; link=$3 }); -} - -# send notification via e-mail - expects one array argument -:set SendEMail2 do={ - :local Notification $1; - - :global NotificationFunctions; - - ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; -} diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc new file mode 100644 index 0000000..0d83d69 --- /dev/null +++ b/mod/notification-email.rsc @@ -0,0 +1,240 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-email +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# send notifications via e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/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={ + :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 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={ + /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler; + } + + :if ([ /tool/e-mail/get last-status ] = "in-progress") do={ + $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; + } + + :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={ + $LogPrint warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty."); + } + + /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler; + + :foreach Id,Message in=$EmailQueue do={ + :if ([ :typeof $Message ] = "array" ) do={ + :local Attach ({}); + :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; } + :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ + :if ([ :len [ /file/find where name=$File ] ] = 1) do={ + :set Attach ($Attach, $File); + } else={ + $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; + } else={ + /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler; + } +} + +# generate filter for log-forward +:set LogForwardFilterLogForwarding do={ + :global EscapeForRegEx; + :global NotificationEMailSubject; + :global SymbolForNotification; + + :return ("^Error sending e-mail <(" . \ + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "memo" ] . "Log Forwarding") ] ] . "|" . \ + [ $EscapeForRegEx [ $NotificationEMailSubject ([ $SymbolForNotification \ + "warning-sign" ] . "Log Forwarding") ] ] . ")>:"); +} + +# generate the e-mail subject +:set NotificationEMailSubject do={ + :global Identity; + :global IdentityExtra; + + :global QuotedPrintable; + + :return [ $QuotedPrintable ("[" . $IdentityExtra . $Identity . "] " . $1) ]; +} + +# send notification via e-mail - expects one array argument +:set ($NotificationFunctions->"email") do={ + :local Notification $1; + + :global EmailGeneralTo; + :global EmailGeneralToOverride; + :global EmailGeneralCc; + :global EmailGeneralCcOverride; + :global EmailQueue; + + :global EitherOr; + :global IfThenElse; + :global 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={ + :global SendEMail2; + + $SendEMail2 ({ subject=$1; message=$2; link=$3 }); +} + +# send notification via e-mail - expects one array argument +:set SendEMail2 do={ + :local Notification $1; + + :global NotificationFunctions; + + ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification; +} diff --git a/mod/notification-matrix b/mod/notification-matrix.rsc index 5a5f8cf..aa95841 100644 --- a/mod/notification-matrix +++ b/mod/notification-matrix.rsc @@ -1,31 +1,37 @@ #!rsc by RouterOS # RouterOS script: mod/notification-matrix -# Copyright (c) 2013-2022 Michael Gisbers <michael@gisbers.de> +# Copyright (c) 2013-2024 Michael Gisbers <michael@gisbers.de> # Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Matrix +# https://git.eworm.de/cgit/routeros-scripts/about/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={ :global MatrixQueue; :global IsFullyConnected; - :global LogPrintExit2; + :global LogPrint; :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + $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=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Matrix messages from scheduler, but queue is empty.") false; + :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={ @@ -39,14 +45,14 @@ $Message->"formatted" . "\" }") as-value; :set ($MatrixQueue->$Id); } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Matrix message failed.") false; + $LogPrint debug $0 ("Sending queued Matrix message failed."); :set AllDone false; } } } :if ($AllDone = true && $QueueLen = [ :len $MatrixQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_FlushMatrixQueue" ]; :set MatrixQueue; } } @@ -56,6 +62,7 @@ :local Notification $1; :global Identity; + :global IdentityExtra; :global MatrixAccessToken; :global MatrixAccessTokenOverride; :global MatrixHomeServer; @@ -65,7 +72,7 @@ :global MatrixRoomOverride; :global EitherOr; - :global LogPrintExit2; + :global LogPrint; :global SymbolForNotification; :local PrepareText do={ @@ -106,10 +113,11 @@ :return false; } - :local Plain [ $PrepareText ("## [" . $Identity . "] " . ($Notification->"subject") . "\n```\n" . \ - ($Notification->"message") . "\n```") "plain" ]; - :local Formatted ("<h2>" . [ $PrepareText ("[" . $Identity . "] " . ($Notification->"subject")) "format" ] . "</h2>" . \ - "<pre><code>" . [ $PrepareText ($Notification->"message") "format" ] . "</code></pre>"); + :local Plain [ $PrepareText ("## [" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject") . "\n```\n" . ($Notification->"message") . "\n```") "plain" ]; + :local Formatted ("<h2>" . [ $PrepareText ("[" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject")) "format" ] . "</h2>" . "<pre><code>" . \ + [ $PrepareText ($Notification->"message") "format" ] . "</code></pre>"); :if ([ :len ($Notification->"link") ] > 0) do={ :set Plain ($Plain . "\\n" . [ $SymbolForNotification "link" ] . \ [ $PrepareText ("[" . $Notification->"link" . "](" . $Notification->"link" . ")") "plain" ]); @@ -126,7 +134,7 @@ "\"format\": \"org.matrix.custom.html\", \"formatted_body\": \"" . \ $Formatted . "\" }") as-value; } on-error={ - $LogPrintExit2 info $0 ("Failed sending Matrix notification! Queuing...") false; + $LogPrint info $0 ("Failed sending Matrix notification! Queuing..."); :if ([ :typeof $MatrixQueue ] = "nothing") do={ :set MatrixQueue ({}); @@ -139,13 +147,21 @@ :set ($MatrixQueue->[ :len $MatrixQueue ]) { room=$Room; \ accesstoken=$AccessToken; homeserver=$HomeServer; \ plain=$Plain; formatted=$Formatted }; - :if ([ :len [ /system/scheduler/find where name="\$FlushMatrixQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushMatrixQueue" interval=1m start-time=startup \ + :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={ :global SendMatrix2; @@ -161,3 +177,84 @@ ($NotificationFunctions->"matrix") ("\$NotificationFunctions->\"matrix\"") $Notification; } + +# setup - get home server and access token +:set SetupMatrixAuthenticate do={ + :local User [ :tostr $1 ]; + :local Pass [ :tostr $2 ]; + + :global CharacterReplace; + :global LogPrint; + :global ParseJson; + + :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 \ + ("https://" . $Domain . "/.well-known/matrix/client") as-value ]->"data"); + :set MatrixHomeServer ([ $ParseJson ([ $ParseJson [ $CharacterReplace $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-method=post http-data=("{\"type\":\"m.login.password\", \"user\":\"" . $User . "\", \"password\":\"" . $Pass . "\"}") \ + ("https://" . $MatrixHomeServer . "/_matrix/client/r0/login") as-value ]->"data"); + :set MatrixAccessToken ([ $ParseJson $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/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + ":global MatrixHomeServer \"" . $MatrixHomeServer . "\";\n" . \ + ":global MatrixAccessToken \"" . $MatrixAccessToken . "\";\n"); + $LogPrint info $0 ("Appended configuration to global-config-overlay. Now create and join a room, please!"); + } on-error={ + $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + :return false; + } +} + +# setup - join a room +:set SetupMatrixJoinRoom do={ + :global MatrixRoom [ :tostr $1 ]; + + :global LogPrint; + :global UrlEncode; + + :global MatrixAccessToken; + :global MatrixHomeServer; + :global MatrixRoom; + + :do { + /tool/fetch check-certificate=yes-without-crl output=none \ + 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 { + /system/script/set global-config-overlay source=([ get global-config-overlay source ] . "\n" . \ + ":global MatrixRoom \"" . $MatrixRoom . "\";\n"); + $LogPrint info $0 ("Appended configuration to global-config-overlay. Please review and cleanup!"); + } on-error={ + $LogPrint error $0 ("Failed appending configuration to global-config-overlay!"); + :return false; + } +} diff --git a/mod/notification-ntfy.rsc b/mod/notification-ntfy.rsc new file mode 100644 index 0000000..6d48a59 --- /dev/null +++ b/mod/notification-ntfy.rsc @@ -0,0 +1,136 @@ +#!rsc by RouterOS +# RouterOS script: mod/notification-ntfy +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Ntfy (ntfy.sh) +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-ntfy.md + +:global FlushNtfyQueue; +:global NotificationFunctions; +:global PurgeNtfyQueue; +:global SendNtfy; +:global SendNtfy2; + +# flush ntfy queue +:set FlushNtfyQueue 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 \ + ($Message->"url") http-header-field=($Message->"headers") http-data=($Message->"text") 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; + } +} + +# 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 NtfyTopic; + :global NtfyTopicOverride; + + :global CertificateAvailable; + :global EitherOr; + :global IfThenElse; + :global LogPrint; + :global SymbolForNotification; + :global UrlEncode; + + :local Server [ $EitherOr ($NtfyServerOverride->($Notification->"origin")) $NtfyServer ]; + :local Topic [ $EitherOr ($NtfyTopicOverride->($Notification->"origin")) $NtfyTopic ]; + + :if ([ :len $Topic ] = 0) do={ + :return false; + } + + :local Url ("https://" . $NtfyServer . "/" . [ $UrlEncode $NtfyTopic ]); + :local Headers ({ ("Priority: " . [ $IfThenElse ($Notification->"silent") "low" "default" ]); \ + ("Title: " . "[" . $IdentityExtra . $Identity . "] " . ($Notification->"subject")) }); + :local Text (($Notification->"message") . "\n"); + :if ([ :len ($Notification->"link") ] > 0) do={ + :set Text ($Text . "\n" . [ $SymbolForNotification "link" ] . ($Notification->"link")); + } + + :do { + :if ($NtfyServer = "ntfy.sh") do={ + :if ([ $CertificateAvailable "R3" ] = false) do={ + $LogPrint warning $0 ("Downloading required certificate failed."); + :error false; + } + } + /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + $Url http-header-field=$Headers http-data=$Text 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={ + :global SendNtfy2; + + $SendNtfy2 ({ subject=$1; message=$2; link=$3; silent=$4 }); +} + +# 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 b/mod/notification-telegram.rsc index 849740b..506ec80 100644 --- a/mod/notification-telegram +++ b/mod/notification-telegram.rsc @@ -1,51 +1,58 @@ #!rsc by RouterOS # RouterOS script: mod/notification-telegram -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# send notifications via Telegram +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/notification-telegram.md :global FlushTelegramQueue; :global NotificationFunctions; +:global PurgeTelegramQueue; :global SendTelegram; :global SendTelegram2; # flush telegram queue :set FlushTelegramQueue do={ :global TelegramQueue; + :global TelegramMessageIDs; :global IsFullyConnected; - :global LogPrintExit2; + :global LogPrint; + :global ParseJson; + :global UrlEncode; :if ([ $IsFullyConnected ] = false) do={ - $LogPrintExit2 debug $0 ("System is not fully connected, not flushing.") false; + $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=$0 ] ] > 0 && $QueueLen = 0) do={ - $LogPrintExit2 warning $0 ("Flushing Telegram messages from scheduler, but queue is empty.") false; + :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 { - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . ($Message->"tokenid") . "/sendMessage") \ - http-data=("chat_id=" . ($Message->"chatid") . \ - "&disable_notification=" . ($Message->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . ($Message->"parsemode") . \ - "&text=" . ($Message->"text")) as-value; + http-data=("chat_id=" . ($Message->"chatid") . "&disable_notification=" . ($Message->"silent") . \ + "&reply_to_message_id=" . ($Message->"replyto") . "&disable_web_page_preview=true" . \ + "&parse_mode=MarkdownV2&text=" . [ $UrlEncode ($Message->"text") ]) as-value ]->"data"); :set ($TelegramQueue->$Id); + :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ - $LogPrintExit2 debug $0 ("Sending queued Telegram message failed.") false; + $LogPrint debug $0 ("Sending queued Telegram message failed."); :set AllDone false; } } } :if ($AllDone = true && $QueueLen = [ :len $TelegramQueue ]) do={ - /system/scheduler/remove [ find where name=$0 ]; + /system/scheduler/remove [ find where name="_FlushTelegramQueue" ]; :set TelegramQueue; } } @@ -55,9 +62,10 @@ :local Notification $1; :global Identity; + :global IdentityExtra; :global TelegramChatId; :global TelegramChatIdOverride; - :global TelegramFixedWidthFont; + :global TelegramMessageIDs; :global TelegramQueue; :global TelegramTokenId; :global TelegramTokenIdOverride; @@ -66,20 +74,15 @@ :global CharacterReplace; :global EitherOr; :global IfThenElse; - :global LogPrintExit2; + :global LogPrint; + :global ParseJson; :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"={ "\\"; "`" }; @@ -97,15 +100,21 @@ :return $Return; } - :local ChatId [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ]; + :local ChatId [ $EitherOr ($Notification->"chatid") \ + [ $EitherOr ($TelegramChatIdOverride->($Notification->"origin")) $TelegramChatId ] ]; :local TokenId [ $EitherOr ($TelegramTokenIdOverride->($Notification->"origin")) $TelegramTokenId ]; :if ([ :len $TokenId ] = 0 || [ :len $ChatId ] = 0) do={ :return false; } + :if ([ :typeof $TelegramMessageIDs ] = "nothing") do={ + :set TelegramMessageIDs ({}); + } + :local Truncated false; - :local Text ("*__" . [ $EscapeMD ("[" . $Identity . "] " . ($Notification->"subject")) "plain" ] . "__*\n\n"); + :local Text ("*__" . [ $EscapeMD ("[" . $IdentityExtra . $Identity . "] " . \ + ($Notification->"subject")) "plain" ] . "__*\n\n"); :local LenSubject [ :len $Text ]; :local LenMessage [ :len ($Notification->"message") ]; :local LenLink [ :len ($Notification->"link") ]; @@ -121,38 +130,47 @@ } :if ($Truncated = true) do={ :set Text ($Text . "\n" . [ $SymbolForNotification "scissors" ] . \ - [ $EscapeMD ("The Telegram message was too long and has been truncated, cut off " . \ + [ $EscapeMD ("The message was too long and has been truncated, cut off " . \ (($LenSum - [ :len $Text ]) * 100 / $LenSum) . "%!") "plain" ]); } - :set Text [ $UrlEncode $Text ]; - :local ParseMode [ $IfThenElse ($TelegramFixedWidthFont = true) "MarkdownV2" "" ]; :do { :if ([ $CertificateAvailable "Go Daddy Secure Certificate Authority - G2" ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; + $LogPrint warning $0 ("Downloading required certificate failed."); + :error false; } - /tool/fetch check-certificate=yes-without-crl output=none http-method=post \ + :local Data ([ /tool/fetch check-certificate=yes-without-crl output=user http-method=post \ ("https://api.telegram.org/bot" . $TokenId . "/sendMessage") \ http-data=("chat_id=" . $ChatId . "&disable_notification=" . ($Notification->"silent") . \ - "&disable_web_page_preview=true&parse_mode=" . $ParseMode . "&text=" . $Text) as-value; + "&reply_to_message_id=" . ($Notification->"replyto") . "&disable_web_page_preview=true" . \ + "&parse_mode=MarkdownV2&text=" . [ $UrlEncode $Text ]) as-value ]->"data"); + :set ($TelegramMessageIDs->([ $ParseJson ([ $ParseJson $Data ]->"result") ]->"message_id")) 1; } on-error={ - $LogPrintExit2 info $0 ("Failed sending telegram notification! Queuing...") false; + $LogPrint info $0 ("Failed sending telegram notification! Queuing..."); :if ([ :typeof $TelegramQueue ] = "nothing") do={ :set TelegramQueue ({}); } - :set Text ($Text . [ $UrlEncode ("\n" . [ $SymbolForNotification "alarm-clock" ] . \ + :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" ]) ]); + " " . [ /system/clock/get time ] . " and may be obsolete.") "plain" ]); :set ($TelegramQueue->[ :len $TelegramQueue ]) { chatid=$ChatId; tokenid=$TokenId; - parsemode=$ParseMode; text=$Text; silent=($Notification->"silent") }; - :if ([ :len [ /system/scheduler/find where name="\$FlushTelegramQueue" ] ] = 0) do={ - /system/scheduler/add name="\$FlushTelegramQueue" interval=1m start-time=startup \ + text=$Text; silent=($Notification->"silent"); replyto=($Notification->"replyto") }; + :if ([ :len [ /system/scheduler/find where name="_FlushTelegramQueue" ] ] = 0) do={ + /system/scheduler/add name="_FlushTelegramQueue" interval=1m start-time=startup \ on-event=(":global FlushTelegramQueue; \$FlushTelegramQueue;"); } } } +# 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={ :global SendTelegram2; diff --git a/mod/scriptrunonce b/mod/scriptrunonce.rsc index 6cca175..85d465a 100644 --- a/mod/scriptrunonce +++ b/mod/scriptrunonce.rsc @@ -1,7 +1,10 @@ #!rsc by RouterOS # RouterOS script: mod/scriptrunonece -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download script and run it once +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/scriptrunonce.md :global ScriptRunOnce; @@ -12,34 +15,35 @@ :global ScriptRunOnceBaseUrl; :global ScriptRunOnceUrlSuffix; - :global LogPrintExit2; + :global LogPrint; :global ValidateSyntax; :foreach Script in=$Scripts do={ - :if (!($Script ~ "^(ftp|https\?|sftp)://")) do={ + :if (!($Script ~ "^(ftp|https?|sftp)://")) do={ :if ([ :len $ScriptRunOnceBaseUrl ] = 0) do={ - $LogPrintExit2 warning $0 ("Script '" . $Script . "' is not an url and base url is not available.") true; + $LogPrint warning $0 ("Script '" . $Script . "' is not an url and base url is not available."); + :return false; } - :set Script ($ScriptRunOnceBaseUrl . $Script . $ScriptRunOnceUrlSuffix); + :set Script ($ScriptRunOnceBaseUrl . $Script . ".rsc" . $ScriptRunOnceUrlSuffix); } :local Source; :do { :set Source ([ /tool/fetch check-certificate=yes-without-crl $Script output=user as-value ]->"data"); } on-error={ - $LogPrintExit2 warning $0 ("Failed fetching script '" . $Script . "'!") false; + $LogPrint warning $0 ("Failed fetching script '" . $Script . "'!"); } :if ([ :len $Source ] > 0) do={ :if ([ $ValidateSyntax $Source ] = true) do={ :do { - $LogPrintExit2 info $0 ("Running script '" . $Script . "' now.") false; + $LogPrint info $0 ("Running script '" . $Script . "' now."); [ :parse $Source ]; } on-error={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed to run!") false; + $LogPrint warning $0 ("The script '" . $Script . "' failed to run!"); } } else={ - $LogPrintExit2 warning $0 ("The script '" . $Script . "' failed syntax validation!") false; + $LogPrint warning $0 ("The script '" . $Script . "' failed syntax validation!"); } } } diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc new file mode 100644 index 0000000..6716958 --- /dev/null +++ b/mod/ssh-keys-import.rsc @@ -0,0 +1,112 @@ +#!rsc by RouterOS +# RouterOS script: mod/ssh-keys-import +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# import ssh keys for public key authentication +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mod/ssh-keys-import.md + +:global SSHKeysImport; +:global SSHKeysImportFile; + +# import single key passed as string +:set SSHKeysImport do={ + :local Key [ :tostr $1 ]; + :local User [ :tostr $2 ]; + + :global CharacterReplace; + :global GetRandom20CharAlNum; + :global LogPrint; + :global MkDir; + :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 [ :toarray [ $CharacterReplace $Key " " "," ] ]; + :if (!($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa")) do={ + $LogPrint warning $0 ("SSH key of type '" . $KeyVal->0 . "' is not supported."); + :return false; + } + + :if ([ $MkDir "tmpfs/ssh-keys-import" ] = false) do={ + $LogPrint warning $0 ("Creating directory 'tmpfs/ssh-keys-import' failed!"); + :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; + } + + :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 . "'."); + } on-error={ + $LogPrint warning $0 ("Failed importing key."); + :return false; + } +} + +# import keys from a file +:set SSHKeysImportFile do={ + :local FileName [ :tostr $1 ]; + :local User [ :tostr $2 ]; + + :global CharacterReplace; + :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 ([ /file/get $FileName contents ] . "\n"); + + :do { + :local Continue false; + :local Line [ :pick $Keys 0 [ :find $Keys "\n" ] ]; + :set Keys [ :pick $Keys ([ :find $Keys "\n" ] + 1) [ :len $Keys ] ]; + :local KeyVal [ :toarray [ $CharacterReplace $Line " " "," ] ]; + :if ($KeyVal->0 = "ssh-ed25519" || $KeyVal->0 = "ssh-rsa") do={ + :do { + $SSHKeysImport $Line $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 [ :pick $Line 2 [ :len $Line ] ] ]->"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."); + } + } while=([ :len $Keys ] > 0); +} diff --git a/mode-button b/mode-button deleted file mode 100644 index e4d33cc..0000000 --- a/mode-button +++ /dev/null @@ -1,76 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: mode-button -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# act on multiple mode and reset button presses -# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md - -:local 0 "mode-button"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global ModeButton; - -:global LogPrintExit2; - -:set ($ModeButton->"count") ($ModeButton->"count" + 1); - -:local Scheduler [ /system/scheduler/find where name="ModeButtonScheduler" ]; - -:if ([ :len $Scheduler ] = 0) do={ - $LogPrintExit2 info $0 ("Creating scheduler ModeButtonScheduler, counting presses...") false; - :global ModeButtonScheduler do={ - :global ModeButton; - - :global LogPrintExit2; - :global ModeButtonScheduler; - :global ValidateSyntax; - - :local LEDInvert do={ - :global ModeButtonLED; - - :global IfThenElse; - - :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; - :if ([ :len $LED ] = 0) do={ - :return false; - } - /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; - } - - :local Count ($ModeButton->"count"); - :local Code ($ModeButton->[ :tostr $Count ]); - - :set ($ModeButton->"count") 0; - :set ModeButtonScheduler; - /system/scheduler/remove ModeButtonScheduler; - - :if ([ :len $Code ] > 0) do={ - :if ([ $ValidateSyntax $Code ] = true) do={ - $LogPrintExit2 info $0 ("Acting on " . $Count . " mode-button presses: " . $Code) false; - - :for I from=1 to=$Count do={ - $LEDInvert; - :if ([ /system/routerboard/settings/get silent-boot ] = false) do={ - :beep length=200ms; - } - :delay 200ms; - $LEDInvert; - :delay 200ms; - } - - [ :parse $Code ]; - } else={ - $LogPrintExit2 warning $0 ("The code for " . $Count . " mode-button presses failed syntax validation!") false; - } - } else={ - $LogPrintExit2 info $0 ("No action defined for " . $Count . " mode-button presses.") false; - } - } - /system/scheduler/add name="ModeButtonScheduler" \ - on-event=":global ModeButtonScheduler; \$ModeButtonScheduler;" interval=3s; -} else={ - $LogPrintExit2 debug $0 ("Updating scheduler ModeButtonScheduler...") false; - /system/scheduler/set $Scheduler start-time=[ /system/clock/get time ]; -} diff --git a/mode-button.rsc b/mode-button.rsc new file mode 100644 index 0000000..f453f11 --- /dev/null +++ b/mode-button.rsc @@ -0,0 +1,81 @@ +#!rsc by RouterOS +# RouterOS script: mode-button +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# act on multiple mode and reset button presses +# https://git.eworm.de/cgit/routeros-scripts/about/doc/mode-button.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :global ModeButton; + + :global LogPrint; + :global ModeButtonScheduler; + :global ValidateSyntax; + + :local LEDInvert do={ + :global ModeButtonLED; + + :global IfThenElse; + + :local LED [ /system/leds/find where leds=$ModeButtonLED type~"^(on|off)\$" interface=[] ]; + :if ([ :len $LED ] = 0) do={ + :return false; + } + /system/leds/set type=[ $IfThenElse ([ get $LED type ] = "on") "off" "on" ] $LED; + } + + :local Count ($ModeButton->"count"); + :local Code ($ModeButton->[ :tostr $Count ]); + + :set ($ModeButton->"count") 0; + :set ModeButtonScheduler; + /system/scheduler/remove [ find where name="_ModeButtonScheduler" ]; + + :if ([ :len $Code ] > 0) do={ + :if ([ $ValidateSyntax $Code ] = true) do={ + $LogPrint info $ScriptName ("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; + } + + [ :parse $Code ]; + } else={ + $LogPrint warning $ScriptName ("The code for " . $Count . " mode-button presses failed syntax validation!"); + } + } else={ + $LogPrint info $ScriptName ("No action defined for " . $Count . " mode-button presses."); + } + } + /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={ } diff --git a/netwatch-dns b/netwatch-dns deleted file mode 100644 index f828de0..0000000 --- a/netwatch-dns +++ /dev/null @@ -1,94 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: netwatch-dns -# Copyright (c) 2022 Christian Hesse <mail@eworm.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# monitor and manage dns/doh with netwatch -# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md - -:local 0 "netwatch-dns"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertificateAvailable; -:global EitherOr; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; - -$ScriptLock $0; - -:if ([ /system/resource/get uptime ] < 5m) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; -} - -:local DnsServers ({}); -:local DnsFallback ({}); -:local DnsCurrent [ /ip/dns/get servers ]; - -:foreach Host in=[ /tool/netwatch/find where comment~"dns" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - - :if ($HostVal->"status" = "up" && $HostInfo->"disabled" != true) do={ - :if ($HostInfo->"dns" = true) do={ - :set DnsServers ($DnsServers, $HostVal->"host"); - } - :if ($HostInfo->"dns-fallback" = true) do={ - :set DnsFallback ($DnsFallback, $HostVal->"host"); - } - } -} - -:if ([ :len $DnsServers ] > 0) do={ - :if ($DnsServers != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers: " . [ :tostr $DnsServers ]) false; - /ip/dns/set servers=$DnsServers; - /ip/dns/cache/flush; - } -} else={ - :if ([ :len $DnsFallback ] > 0) do={ - :if ($DnsFallback != $DnsCurrent) do={ - $LogPrintExit2 info $0 ("Updating DNS servers to fallback: " . \ - [ :tostr $DnsFallback ]) false; - /ip/dns/set servers=$DnsFallback; - /ip/dns/cache/flush; - } - } -} - -:local DohServer ""; -:local DohCurrent [ /ip/dns/get use-doh-server ]; -:local DohCert ""; - -:foreach Host in=[ /tool/netwatch/find where comment~"doh" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local HostInfo [ $ParseKeyValueStore ($HostVal->"comment") ]; - - :if ($HostVal->"status" = "up" && $HostInfo->"doh" = true && \ - $HostInfo->"disabled" != true && $DohServer = "") do={ - :set DohServer [ $EitherOr ($HostInfo->"doh-url") \ - ("https://" . $HostVal->"host" . "/dns-query") ]; - :set DohCert ($HostInfo->"doh-cert"); - } -} - -:if ($DohServer != "") do={ - :if ($DohServer != $DohCurrent) do={ - $LogPrintExit2 info $0 ("Updating DoH server: " . $DohServer) false; - :if ([ :len $DohCert ] > 0) do={ - /ip/dns/set use-doh-server=""; - :if ([ $CertificateAvailable $DohCert ] = false) do={ - $LogPrintExit2 warning $0 ("Downloading certificate failed, trying without.") false; - } - } - /ip/dns/set use-doh-server=$DohServer; - /ip/dns/cache/flush; - } -} else={ - :if ($DohCurrent != "") do={ - $LogPrintExit2 info $0 ("DoH server (" . $DohCurrent . ") is down, disabling.") false; - /ip/dns/set use-doh-server=""; - /ip/dns/cache/flush; - } -} diff --git a/netwatch-dns.rsc b/netwatch-dns.rsc new file mode 100644 index 0000000..50c2b4c --- /dev/null +++ b/netwatch-dns.rsc @@ -0,0 +1,130 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-dns +# Copyright (c) 2022-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# monitor and manage dns/doh with netwatch +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-dns.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CertificateAvailable; + :global EitherOr; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :local SettleTime (5m30s - [ /system/resource/get uptime ]); + :if ($SettleTime > 0s) do={ + $LogPrint info $ScriptName ("System just booted, giving netwatch " . $SettleTime . " to settle."); + :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 ({}); + + :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 or 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); + :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; + /ip/dns/cache/flush; + $LogPrint info $ScriptName ("Setting DoH server: " . ($DohServer->"doh-url")); + :error true; + } else={ + $LogPrint warning $ScriptName ("Received unexpected response from DoH server: " . \ + ($DohServer->"doh-url")); + } + } + } +} on-error={ } diff --git a/netwatch-notify b/netwatch-notify deleted file mode 100644 index f95f426..0000000 --- a/netwatch-notify +++ /dev/null @@ -1,180 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: netwatch-notify -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "netwatch-notify"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global NetwatchNotify; - -:global EitherOr; -:global IfThenElse; -:global IsDNSResolving; -:global LogPrintExit2; -:global ParseKeyValueStore; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; - -:local NetwatchNotifyHook do={ - :local Name [ :tostr $1 ]; - :local Type [ :tostr $2 ]; - :local State [ :tostr $3 ]; - :local Hook [ :tostr $4 ]; - - :global LogPrintExit2; - :global ValidateSyntax; - - :if ([ $ValidateSyntax $Hook ] = true) do={ - :do { - [ :parse $Hook ]; - } on-error={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed to run.") false; - :return ("The hook failed to run."); - } - } else={ - $LogPrintExit2 warning $0 ("The " . $State . "-hook for " . $Type . " '" . $Name . \ - "' failed syntax validation.") false; - :return ("The hook failed syntax validation."); - } - - $LogPrintExit2 info $0 ("Ran hook on " . $Type . " '" . $Name . "' " . $State . ": " . \ - $Hook) false; - :return ("Ran hook:\n" . $Hook); -} - -$ScriptLock $0; - -:if ([ /system/resource/get uptime ] < 5m) do={ - $LogPrintExit2 info $0 ("System just booted, giving netwatch some time to settle.") true; -} - -:if ([ :typeof $NetwatchNotify ] = "nothing") do={ - :set NetwatchNotify ({}); -} - -:foreach Host in=[ /tool/netwatch/find where comment~"notify" !disabled ] do={ - :local HostVal [ /tool/netwatch/get $Host ]; - :local Type [ $IfThenElse ($HostVal->"type" ~ "^(http-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 ($HostInfo->"resolve") ]; - :if ($Resolve != $HostVal->"host") do={ - $LogPrintExit2 info $0 ("Name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' resolves to different address " . $Resolve . \ - ", updating.") false; - /tool/netwatch/set host=$Resolve $Host; - :set ($Metric->"resolve-failcnt") 0; - } - } on-error={ - :set ($Metric->"resolve-failcnt") ($Metric->"resolve-failcnt" + 1); - :if ($Metric->"resolve-failcnt" = 3) do={ - $LogPrintExit2 warning $0 ("Resolving name '" . $HostInfo->"resolve" . [ $IfThenElse \ - ($HostInfo->"resolve" != $HostInfo->"name") ("' for " . $Type . " '" . \ - $HostInfo->"name") "" ] . "' failed.") false; - } - } - } - } - - :if ($HostVal->"status" = "up") do={ - :local CountDown ($Metric->"count-down"); - :if ($CountDown > 0) do={ - $LogPrintExit2 info $0 \ - ("The " . $Type . " '" . $Name . "' (" . $HostDetails . ") is up.") false; - :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->"up-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "up" \ - ($HostInfo->"up-hook") ]); - } - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Netwatch Notify: " . \ - $Name . " up"); \ - message=$Message }); - } - :set ($Metric->"notified") false; - :set ($Metric->"parent") ($HostInfo->"parent"); - :set ($Metric->"since"); - } else={ - :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-down") ] > 0) ($HostInfo->"count-down") 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"); - } - } - $LogPrintExit2 [ $IfThenElse ($HostInfo->"no-down-notification" != true) info debug ] $0 \ - ("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.") ]) false; - :if ((($CountDown * 2) - ($Metric->"count-down" * 3)) / 2 = 0 && \ - [ :typeof ($HostInfo->"pre-down-hook") ] = "str") do={ - $NetwatchNotifyHook $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->"down-hook") ] = "str") do={ - :set Message ($Message . "\n\n" . [ $NetwatchNotifyHook $Name $Type "down" \ - ($HostInfo->"down-hook") ]); - } - :if ($HostInfo->"no-down-notification" != true) do={ - $SendNotification2 ({ origin=$0; \ - subject=([ $SymbolForNotification "cross-mark" ] . "Netwatch Notify: " . \ - $Name . " down"); \ - message=$Message }); - } - :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") }; - } -} diff --git a/netwatch-notify.rsc b/netwatch-notify.rsc new file mode 100644 index 0000000..bdabe2e --- /dev/null +++ b/netwatch-notify.rsc @@ -0,0 +1,219 @@ +#!rsc by RouterOS +# RouterOS script: netwatch-notify +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# monitor netwatch and send notifications +# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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 ]); + /ip/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ip/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } + /ipv6/firewall/address-list/add address=$Name list=$FwAddrList dynamic=yes timeout=1s; + :delay 20ms; + :if ([ :len [ /ipv6/firewall/address-list/find where list=$FwAddrList address=$Expected ] ] > 0) do={ + :return true; + } + + :return false; + } + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 ($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 warning $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={ } diff --git a/news-and-changes.rsc b/news-and-changes.rsc new file mode 100644 index 0000000..1f1094d --- /dev/null +++ b/news-and-changes.rsc @@ -0,0 +1,60 @@ +# News, changes and migration by RouterOS Scripts +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/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."; +}; + +# 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\\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; }"; +}; diff --git a/ospf-to-leds b/ospf-to-leds deleted file mode 100644 index c4acb30..0000000 --- a/ospf-to-leds +++ /dev/null @@ -1,35 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ospf-to-leds -# Copyright (c) 2020-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "ospf-to-leds"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; -: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 ]; - - :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={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has " . $NeighborCount . " neighbors, led on!") false; - /system/leds/set type=on [ find where leds=$LED ]; - } - :if ($NeighborCount = 0 && $LEDType = "on") do={ - $LogPrintExit2 info $0 ("OSPF instance " . $InstanceVal->"name" . " has no neighbors, led off!") false; - /system/leds/set type=off [ find where leds=$LED ]; - } -} diff --git a/ospf-to-leds.rsc b/ospf-to-leds.rsc new file mode 100644 index 0000000..a22e5a5 --- /dev/null +++ b/ospf-to-leds.rsc @@ -0,0 +1,45 @@ +#!rsc by RouterOS +# RouterOS script: ospf-to-leds +# Copyright (c) 2020-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# visualize ospf instance state via leds +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ospf-to-leds.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/packages-update b/packages-update deleted file mode 100644 index 2922759..0000000 --- a/packages-update +++ /dev/null @@ -1,93 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: packages-update -# Copyright (c) 2019-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "packages-update"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global DownloadPackage; -:global LogPrintExit2; -:global ScriptFromTerminal; -:global ScriptLock; -:global VersionToNum; - -$ScriptLock $0; - -:local Update [ /system/package/update/get ]; - -:if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ - $LogPrintExit2 warning $0 ("Latest version is not known.") true; -} - -:if ($Update->"installed-version" = $Update->"latest-version") do={ - $LogPrintExit2 info $0 ("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 $0 ] = 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={ - $LogPrintExit2 warning $0 ("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={ - $LogPrintExit2 error $0 ("Download for package " . $PkgName . " failed, update aborted.") true; - } -} - -:foreach Script in=[ /system/script/find where source~"\n# provides: backup-script\n" ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrintExit2 info $0 ("Running backup script " . $ScriptName . " before update.") false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running backup script " . $ScriptName . " before update failed!") false; - :if ([ $ScriptFromTerminal $0 ] = true) do={ - :put "Do you want to continue anyway? [y/N]"; - :if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ - $LogPrintExit2 info $0 ("User requested to continue anyway.") false; - } else={ - $LogPrintExit2 info $0 ("Canceled update...") true; - } - } else={ - $LogPrintExit2 info $0 ("Canceled non-interactive update.") true; - } - } -} - -:if ($DoDowngrade = true) do={ - $LogPrintExit2 info $0 ("Rebooting for downgrade.") false; - :delay 1s; - /system/package/downgrade; -} - -:if ([ $ScriptFromTerminal $0 ] = 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;"); - $LogPrintExit2 info $0 ("Scheduled reboot for update between 03:00 and 04:00.") true; - } -} - -$LogPrintExit2 info $0 ("Rebooting for update.") false; -:delay 1s; -/system/reboot; diff --git a/packages-update.rsc b/packages-update.rsc new file mode 100644 index 0000000..0208b1e --- /dev/null +++ b/packages-update.rsc @@ -0,0 +1,145 @@ +#!rsc by RouterOS +# RouterOS script: packages-update +# Copyright (c) 2019-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.13 +# +# download packages and reboot for installation +# https://git.eworm.de/cgit/routeros-scripts/about/doc/packages-update.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global DownloadPackage; + :global Grep; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptFromTerminal; + :global ScriptLock; + :global VersionToNum; + + :global PackagesUpdateDeferReboot; + :global PackagesUpdateBackupFailure; + + :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={ + :error false; + } + + :local Update [ /system/package/update/get ]; + + :if ([ :typeof ($Update->"latest-version") ] = "nothing") do={ + $LogPrint warning $ScriptName ("Latest version is not known."); + :error false; + } + + :if ($Update->"installed-version" = $Update->"latest-version") do={ + $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is already installed."); + :error true; + } + + :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."); + :error false; + } + } + + :foreach Package in=[ /system/package/find where !bundle ] 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."); + :error false; + } + } + + :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"); + } + + :foreach Order,Script in=$RunOrder do={ + :set PackagesUpdateBackupFailure false; + :do { + $LogPrint info $ScriptName ("Running backup script " . $Script . " before update."); + /system/script/run $Script; + } on-error={ + :set PackagesUpdateBackupFailure true; + } + + :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..."); + :error false; + } + } else={ + $LogPrint warning $ScriptName ("Canceled non-interactive update."); + :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; + :error true; + } + } else={ + :if ($PackagesUpdateDeferReboot = true) do={ + $Schedule $ScriptName; + :error true; + } + } + + $LogPrint info $ScriptName ("Rebooting for update."); + :delay 1s; + /system/reboot; +} on-error={ } diff --git a/ppp-on-up b/ppp-on-up deleted file mode 100644 index 0529352..0000000 --- a/ppp-on-up +++ /dev/null @@ -1,34 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ppp-on-up -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "ppp-on-up"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -:local Interface $interface; - -:if ([ :typeof $Interface ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from ppp on-up script hook.") true; -} - -:local IntName [ /interface/get $Interface name ]; -$LogPrintExit2 info $0 ("PPP interface " . $IntName . " is up.") false; - -/ipv6/dhcp-client/release [ find where interface=$IntName !disabled ]; - -:foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\n") ] do={ - :local ScriptName [ /system/script/get $Script name ]; - :do { - $LogPrintExit2 debug $0 ("Running script: " . $ScriptName) false; - /system/script/run $Script; - } on-error={ - $LogPrintExit2 warning $0 ("Running script '" . $ScriptName . "' failed!") false; - } -} diff --git a/ppp-on-up.rsc b/ppp-on-up.rsc new file mode 100644 index 0000000..61766c0 --- /dev/null +++ b/ppp-on-up.rsc @@ -0,0 +1,40 @@ +#!rsc by RouterOS +# RouterOS script: ppp-on-up +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# run scripts on ppp up +# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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."); + :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 ]; + + :foreach Script in=[ /system/script/find where source~("\n# provides: ppp-on-up\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={ } diff --git a/sms-action b/sms-action deleted file mode 100644 index a1fa4e9..0000000 --- a/sms-action +++ /dev/null @@ -1,31 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: sms-action -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "sms-action"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global SmsAction; - -:global LogPrintExit2; -:global ValidateSyntax; - -:local Action $action; - -:if ([ :typeof $Action ] = "nothing") do={ - $LogPrintExit2 error $0 ("This script is supposed to run from SMS hook with action=...") true; -} - -:local Code ($SmsAction->$Action); -:if ([ $ValidateSyntax $Code ] = true) do={ - :log info ("Acting on SMS action '" . $Action . "': " . $Code); - :delay 1s; - [ :parse $Code ]; -} else={ - $LogPrintExit2 warning $0 ("The code for action '" . $Action . "' failed syntax validation!") false; -} diff --git a/sms-action.rsc b/sms-action.rsc new file mode 100644 index 0000000..4c37565 --- /dev/null +++ b/sms-action.rsc @@ -0,0 +1,37 @@ +#!rsc by RouterOS +# RouterOS script: sms-action +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# run action on received SMS +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-action.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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=..."); + :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={ } diff --git a/sms-forward b/sms-forward deleted file mode 100644 index aa2e71c..0000000 --- a/sms-forward +++ /dev/null @@ -1,62 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: sms-forward -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "sms-forward"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global Identity; - -:global IfThenElse; -:global LogPrintExit2; -:global ScriptLock; -:global SendNotification2; -:global SymbolForNotification; -:global WaitFullyConnected; - -$ScriptLock $0; - -:if ([ /tool/sms/get receive-enabled ] = false) do={ - $LogPrintExit2 warning $0 ("Receiving of SMS is not enabled.") true; -} - -$WaitFullyConnected; - -: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 ({}); - - :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={ - $LogPrintExit2 debug $0 ("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 ]; - $SendNotification2 ({ origin=$0; \ - 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; - } - } -} diff --git a/sms-forward.rsc b/sms-forward.rsc new file mode 100644 index 0000000..b0966c3 --- /dev/null +++ b/sms-forward.rsc @@ -0,0 +1,95 @@ +#!rsc by RouterOS +# RouterOS script: sms-forward +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Anatoly Bubenkov <bubenkoff@gmail.com> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# forward SMS to e-mail +# https://git.eworm.de/cgit/routeros-scripts/about/doc/sms-forward.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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={ + :error false; + } + + :if ([ /tool/sms/get receive-enabled ] = false) do={ + $LogPrintOnce warning $ScriptName ("Receiving of SMS is not enabled."); + :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."); + :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={ } diff --git a/ssh-keys-import b/ssh-keys-import deleted file mode 100644 index 70ddf3d..0000000 --- a/ssh-keys-import +++ /dev/null @@ -1,11 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: ssh-keys-import -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# 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 b/super-mario-theme.rsc index ae52fd1..63308b0 100644 --- a/super-mario-theme +++ b/super-mario-theme.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: super-mario-theme -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # play Super Mario theme diff --git a/telegram-chat.rsc b/telegram-chat.rsc new file mode 100644 index 0000000..9ae5967 --- /dev/null +++ b/telegram-chat.rsc @@ -0,0 +1,180 @@ +#!rsc by RouterOS +# RouterOS script: telegram-chat +# Copyright (c) 2023-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# use Telegram to chat with your Router and send commands +# https://git.eworm.de/cgit/routeros-scripts/about/doc/telegram-chat.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +: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 ParseJson; + :global RandomDelay; + :global ScriptLock; + :global SendTelegram2; + :global SymbolForNotification; + :global ValidateSyntax; + :global WaitForFile; + :global WaitFullyConnected; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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 Secure Certificate Authority - G2" ] = false) do={ + $LogPrint warning $ScriptName ("Downloading required certificate failed."); + :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 from Telegram."); + :error false; + } + + :local UpdateID 0; + :local Uptime [ /system/resource/get uptime ]; + :foreach UpdateArray in=([ $ParseJson $Data ]->"result") do={ + :local Update [ $ParseJson $UpdateArray ]; + :set UpdateID ($Update->"update_id"); + :local Message [ $ParseJson ($Update->"message") ]; + :local IsReply [ :len ($Message->"reply_to_message") ]; + :local IsMyReply ($TelegramMessageIDs->([ $ParseJson ($Message->"reply_to_message") ]->"message_id")); + :if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={ + :local Trusted false; + :local Chat [ $ParseJson ($Message->"chat") ]; + :local From [ $ParseJson ($Message->"from") ]; + + :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 ($Message->"text" = "?") do={ + $LogPrint info $ScriptName ("Sending notice for update " . $UpdateID . "."); + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=("Online" . [ $IfThenElse $TelegramChatActive " (and active!)" ] . ", awaiting your commands!") }); + :set Done true; + } + :if ($Done = false && [ :pick ($Message->"text") 0 1 ] = "!") do={ + :if ($Message->"text" ~ ("^! *(" . [ $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 = 0 && $TelegramChatActive = true)) && [ :len ($Message->"text") ] > 0) do={ + :if ([ $ValidateSyntax ($Message->"text") ] = true) do={ + :local State ""; + :local File ("tmpfs/telegram-chat/" . [ $GetRandom20CharAlNum 6 ]); + :if ([ $MkDir "tmpfs/telegram-chat" ] = false) do={ + $LogPrint error $ScriptName ("Failed creating directory!"); + :error false; + } + $LogPrint info $ScriptName ("Running command from update " . $UpdateID . ": " . $Message->"text"); + :execute script=(":do {\n" . $Message->"text" . "\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/get $File contents ]; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=true; replyto=($Message->"message_id"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\n\n" . \ + $State . [ $IfThenElse ([ :len $Content ] > 0) \ + ([ $SymbolForNotification "memo" ] . "Output:\n" . $Content) [ $IfThenElse ([ /file/get $File size ] > 0) \ + ([ $SymbolForNotification "warning-sign" ] . "Output exceeds file read size.") \ + ([ $SymbolForNotification "memo" ] . "No output.") ] ]) }); + /file/remove "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"); \ + subject=([ $SymbolForNotification "speech-balloon" ] . "Telegram Chat"); \ + message=([ $SymbolForNotification "gear" ] . "Command:\n" . $Message->"text" . "\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 ($Message->"text" ~ ("^! *" . [ $EscapeForRegEx $Identity ] . "\$")) do={ + $LogPrint warning $ScriptName $MessageText; + $SendTelegram2 ({ origin=$ScriptName; chatid=($Chat->"id"); silent=false; replyto=($Message->"message_id"); \ + 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={ } diff --git a/unattended-lte-firmware-upgrade b/unattended-lte-firmware-upgrade.rsc index fafda62..904f952 100644 --- a/unattended-lte-firmware-upgrade +++ b/unattended-lte-firmware-upgrade.rsc @@ -1,6 +1,6 @@ #!rsc by RouterOS # RouterOS script: unattended-lte-firmware-upgrade -# Copyright (c) 2018-2022 Christian Hesse <mail@eworm.de> +# Copyright (c) 2018-2024 Christian Hesse <mail@eworm.de> # https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md # # schedule unattended lte firmware upgrade @@ -24,13 +24,17 @@ :set LTEFirmwareUpgrade; /system/scheduler/remove ($1 . "-firmware-upgrade"); - /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 once as-value ]; - :if (($Firmware->"installed") != ($Firmware->"latest")) do={ - :log warning ("LTE firmware versions still differ. Resetting again..."); - /interface/lte/at-chat $1 input="AT+RESET"; + :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 once as-value ]; + :if (($Firmware->"installed") != ($Firmware->"latest")) do={ + :log warning ("LTE firmware versions still differ. Resetting again..."); + /interface/lte/at-chat $1 input="AT+RESET"; + } + } on-error={ + :log error ("LTE firmware upgrade on '" . $1 . "' failed."); } } diff --git a/update-gre-address b/update-gre-address deleted file mode 100644 index d1402e3..0000000 --- a/update-gre-address +++ /dev/null @@ -1,31 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: update-gre-address -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# 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 - -:local 0 "update-gre-address"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global LogPrintExit2; - -/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={ - $LogPrintExit2 info $0 ("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 new file mode 100644 index 0000000..74967cd --- /dev/null +++ b/update-gre-address.rsc @@ -0,0 +1,42 @@ +#!rsc by RouterOS +# RouterOS script: update-gre-address +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# requires RouterOS, version=7.12 +# +# 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 GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CharacterReplace; + :global LogPrint; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :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={ } diff --git a/update-tunnelbroker b/update-tunnelbroker deleted file mode 100644 index 0075273..0000000 --- a/update-tunnelbroker +++ /dev/null @@ -1,48 +0,0 @@ -#!rsc by RouterOS -# RouterOS script: update-tunnelbroker -# Copyright (c) 2013-2022 Christian Hesse <mail@eworm.de> -# Michael Gisbers <michael@gisbers.de> -# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md -# -# provides: ppp-on-up -# -# update local address of tunnelbroker interface -# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md - -:local 0 "update-tunnelbroker"; -:global GlobalFunctionsReady; -:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } - -:global CertificateAvailable; -:global LogPrintExit2; -:global ParseKeyValueStore; - -:if ([ /ip/cloud/get ddns-enabled ] != true) do={ - $LogPrintExit2 error $0 ("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={ - $LogPrintExit2 error $0 ("Downloading required certificate failed.") true; - } - $LogPrintExit2 info $0 ("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 as-value; - /interface/6to4/set $Interface local-address=$PublicAddress; - } else={ - $LogPrintExit2 debug $0 ("All tunnelbroker configuration is up to date for interface " . $InterfaceVal->"name" . ".") false; - } -} diff --git a/update-tunnelbroker.rsc b/update-tunnelbroker.rsc new file mode 100644 index 0000000..c76b7ec --- /dev/null +++ b/update-tunnelbroker.rsc @@ -0,0 +1,67 @@ +#!rsc by RouterOS +# RouterOS script: update-tunnelbroker +# Copyright (c) 2013-2024 Christian Hesse <mail@eworm.de> +# Michael Gisbers <michael@gisbers.de> +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# provides: ppp-on-up +# requires RouterOS, version=7.12 +# +# update local address of tunnelbroker interface +# https://git.eworm.de/cgit/routeros-scripts/about/doc/update-tunnelbroker.md + +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:do { + :local ScriptName [ :jobname ]; + + :global CertificateAvailable; + :global LogPrint; + :global ParseKeyValueStore; + :global ScriptLock; + + :if ([ $ScriptLock $ScriptName ] = false) do={ + :error false; + } + + :if ([ $CertificateAvailable "Starfield Secure Certificate Authority - G2" ] = false) do={ + $LogPrint error $ScriptName ("Downloading required certificate failed."); + :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!"); + :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={ } |