Compare commits

...

243 commits

Author SHA1 Message Date
Christian Hesse 44fc69e82d packages-update: drop RouterOS version check...
... and allow all updates again. This requires RouterOS 7.13.
2024-03-12 21:39:38 +01:00
Christian Hesse b829ec1fc9 mod/ssh-keys-import: do not exit with error 2024-03-12 20:37:57 +01:00
Christian Hesse 0e2e7efdb2 mod/scriptrunonce: do not exit with error 2024-03-12 20:37:57 +01:00
Christian Hesse c2dc8a0837 mod/notification-matrix: do not exit with error 2024-03-12 20:37:57 +01:00
Christian Hesse 525e4325da mod/bridge-port-vlan: do not exit with error 2024-03-12 20:37:57 +01:00
Christian Hesse 39dd1f2a63 mod/bridge-port-to: do not exit with error 2024-03-12 20:37:57 +01:00
Christian Hesse ba2df80f07 Merge branch 'LogPrint' into next 2024-03-12 20:37:57 +01:00
Christian Hesse 19802c0b69 global-functions: $LogPrintOnce: drop support for exit
This is not widely adopted or used, so let's just drop it - no
compatibility.
2024-03-12 20:37:57 +01:00
Christian Hesse 242ecef012 update-tunnelbroker: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 76f65c13d7 global-functions: add architecture in user-agent string 2024-03-12 20:37:57 +01:00
Christian Hesse 9a21f4d3e3 update-gre-address: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 1c61547284 global-config: merge loading overlay and snippets 2024-03-12 20:37:57 +01:00
Christian Hesse 19fb5c5801 telegram-chat: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse be1aeccbe5 sms-forward: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 5a487d15c2 sms-action: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 88d4c0aff8 ppp-on-up: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 8444e5f270 packages-update: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse ad65b62c1c ospf-to-leds: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 030105cc2e netwatch-notify: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 8ea24540c4 netwatch-dns: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse e3d55819ee mode-button: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse eedf092930 mod/ssh-keys-import: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 8c62c31604 mod/scriptrunonce: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 699f09c282 mod/notification-telegram: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse fb88521ed5 mod/notification-ntfy: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 279993e965 mod/notification-matrix: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 9b8d3f7970 mod/notification-email: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse bdcf43a6f6 mod/bridge-port-vlan: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse b7983d18c4 mod/bridge-port-to: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse f8c79abd38 log-forward: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 29a72e54dc lease-script: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 1f938efcaf ipv6-update: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 56e39123b9 ipsec-to-dns: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 369af47374 hotspot-to-wpa: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse d93ffb9cb2 hotspot-to-wpa-cleanup: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 5c567604ff gps-track: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 9dd1b768ee global-functions: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 6715696ba1 fw-addr-lists: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse c8e4cb0526 firmware-upgrade-reboot: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 5c775fdb3f dhcp-to-dns: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 5638bdcc2d dhcp-lease-comment: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 4ab8dbd774 daily-psk: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 5016f4d28c collect-wireless-mac: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse a996bdac2a check-routeros-update: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 7f154a178b check-lte-firmware-upgrade: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 463393647f check-health: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 3625808749 check-certificates: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 7c38b9a35c certificate-renew-issued: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 12435ff1c5 capsman-rolling-upgrade: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse e40da1e7e4 capsman-download-packages: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse ca822e1358 backup-upload: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse b879f8fef2 backup-partition: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 4b69144ee4 backup-email: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse ac3b755fdc backup-cloud: switch to $LogPrint 2024-03-12 20:37:57 +01:00
Christian Hesse 1feeed145d global-functions: introduce $LogPrint, deprecate $LogPrintExit2 2024-03-12 20:37:57 +01:00
Christian Hesse a7cb3e520a global-config: support loading snippets
This adds support for loading snippets, which need a name starting with
"global-config-overlay.d/". This allows to split off configuration if
desired.
2024-03-12 20:36:21 +01:00
Christian Hesse e39e8a0083 backup-upload: pass failure to packages-update 2024-03-12 15:27:15 +01:00
Christian Hesse 51b00181cf backup-partition: pass failure to packages-update 2024-03-12 15:27:15 +01:00
Christian Hesse 5f41bd1c1e backup-email: pass failure to packages-update 2024-03-12 15:27:15 +01:00
Christian Hesse c82f776632 backup-cloud: pass failure to packages-update 2024-03-12 15:27:15 +01:00
Christian Hesse 3fcdd395fe packages-update: support passing backup failure 2024-03-12 15:27:15 +01:00
Christian Hesse ffa31c7ad7 packages-update: increate log severity on canceled non-interactive update 2024-03-12 15:27:15 +01:00
Christian Hesse 6fd39bd3c5 Merge branch 'do-with-on-error' into next 2024-03-12 15:27:15 +01:00
Christian Hesse b86d631486 doc/telegram-chat: show usage of persistent ids 2024-03-12 15:27:15 +01:00
Christian Hesse f0856c264e update-tunnelbroker: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse a0a2046373 Merge branch 'doc-badges' into next 2024-03-12 15:27:15 +01:00
Christian Hesse febd13af13 update-gre-address: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 09393d3ef5 check-certificates: handle formatting of self signed cert 2024-03-12 15:27:15 +01:00
Christian Hesse 4061661a20 doc/update-tunnelbroker: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 738dd11929 telegram-chat: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 53ff8fbf97 check-certificates: exit block on failed import 2024-03-12 15:27:15 +01:00
Christian Hesse a0a964fa18 doc/update-gre-address: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse ac38e16944 sms-forward: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse a7cd7d9500 Merge branch 'drop-wifiwave2' into next 2024-03-12 15:27:15 +01:00
Christian Hesse 11832a7651 doc/unattended-lte-firmware-upgrade: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse e19a48682e sms-action: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 050ccd490e backup-cloud: add a short delay
Not sure it helps, but chances are...
2024-03-12 15:27:15 +01:00
Christian Hesse 83dbcfecd5 news on wifiwave2 EOL 2024-03-12 15:27:15 +01:00
Christian Hesse 2ac18b1cdf doc/telegram-chat: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 1db1a943e2 ppp-on-up: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 955ee8499b backup-cloud: catch error with :execute workaround
Catching a runtime error here fails... So let's try a workaround
with :execute...
2024-03-12 15:27:15 +01:00
Christian Hesse d513ea61cf hotspot-to-wpa-cleanup: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 8a439ea15c doc/super-mario-theme: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 1012d9fc51 packages-update: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 010bea56dc telegram-chat: error when making directory fails 2024-03-12 15:27:15 +01:00
Christian Hesse 0385c032e2 hotspot-to-wpa: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 3995e85ccf doc/sms-forward: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 850e8db975 ospf-to-leds: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse ed790dea6e mod/notification-email: remove extra spaces 2024-03-12 15:27:15 +01:00
Christian Hesse 074e70ee51 dhcp-lease-comment: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 42d8fed577 doc/sms-action: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 18ed12e3f7 netwatch-notify: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 4e1362aacc mod/inspectvar: remove extra spaces 2024-03-12 15:27:15 +01:00
Christian Hesse decb8fb17a daily-psk: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 2038480b00 doc/ppp-on-up: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 8fcb8efbea netwatch-dns: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 0d35a18c71 global-wait: drop unused variable 2024-03-12 15:27:15 +01:00
Christian Hesse b414608329 collect-wireless-mac: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 4ff543e629 doc/packages-update: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 4dd6bdef31 mode-button: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse c462c0b598 Merge branch 'no-error-on-exit' into next 2024-03-12 15:27:15 +01:00
Christian Hesse e8c5585cc7 capsman-rolling-upgrade: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 6786fbb292 doc/ospf-to-leds: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 52f54baea0 log-forward: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse ada9153636 global-functions: $ScriptLock: fix wording...
... as this does (no longer) abort.
2024-03-12 15:27:15 +01:00
Christian Hesse 34620ba53c capsman-download-packages: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse cdc0db3b81 doc/netwatch-notify: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 6546e7f085 lease-script: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 1e8918fdaa global-functions: $ScriptLock: do not exit from global function 2024-03-12 15:27:15 +01:00
Christian Hesse 9ecc3c4c49 accesslist-duplicates: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse fe83328a57 doc/netwatch-dns: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 6f91c97b7f ipv6-update: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 56e97dd60c global-functions: $DownloadPackage: do not exit from global function 2024-03-12 15:27:15 +01:00
Christian Hesse d799edfc17 Makefile: drop support for wifiwave2 2024-03-12 15:27:15 +01:00
Christian Hesse 2170505beb doc/mode-button: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 341e84682c ipsec-to-dns: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 4004d713aa sms-forward: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 1934c63512 doc/mod/ssh-keys-import: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 54638924e4 hotspot-to-wpa: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse ec90695e8f packages-update: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 564a288c4c doc/mod/scriptrunonce: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse b622f47d65 hotspot-to-wpa-cleanup: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse c6639518bc lease-script: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 4313de6c68 doc/mod/notification-telegram: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 47b67af226 gps-track: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 3acdebad04 hotspot-to-wpa: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse db211a9804 doc/mod/notification-ntfy: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse c1362f54e5 fw-addr-lists: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse ab0b2e27c3 firmware-upgrade-reboot: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 4a08c09129 doc/mod/notification-matrix: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 894c36fc15 firmware-upgrade-reboot: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 184a769eeb check-routeros-update: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse e2823d8746 doc/mod/notification-email: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse ef5972e9f0 dhcp-to-dns: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 5af8b95444 netwatch-dns: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 732b86bb86 doc/mod/ipcalc: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 0d1c4cece2 dhcp-lease-comment: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 6712cc101d check-health: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 73d56b3d5f doc/mod/inspectvar: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse f79206a9b8 daily-psk: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 7fa03ab70e log-forward: do not exit with error 2024-03-12 15:27:15 +01:00
Christian Hesse 9cd84ddffe doc/mod/bridge-port-vlan: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 4ada2e7678 collect-wireless-mac: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 202096c610 doc/mod/bridge-port-to: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 7110b29cba check-routeros-update: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse b6983c8615 doc/log-forward: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse b78556ca41 check-lte-firmware-upgrade: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 91e94c6e38 doc/leds-mode: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 7bf36fa8a5 check-health: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse fd1cb3131d doc/lease-script: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse b1e37c2734 check-certificates: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 8b5c919d8c doc/ipv6-update: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 78f65ead59 certificate-renew-issued: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse c645ab5100 doc/ipsec-to-dns: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 25c9bff6f3 capsman-rolling-upgrade: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse ac51956c3f doc/ip-addr-bridge: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 03309d4fdb capsman-download-packages: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse b45b7606a9 doc/hotspot-to-wpa: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 8d020a4de8 backup-upload: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse e2f6401a15 doc/gps-track: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse b8bd64bac5 backup-partition: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 8ab1df5960 doc/global-wait: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 3eb8fad5ae backup-email: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 900e868caf doc/fw-addr-lists: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 15c68c5660 backup-cloud: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse 2bd2b9b6e3 doc/firmware-upgrade-reboot: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse d0af9d62ea accesslist-duplicates: drop main function, use :do with on-error 2024-03-12 15:27:15 +01:00
Christian Hesse b178e47d6d doc/dhcp-to-dns: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 16b318832a doc/dhcp-lease-comment: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse d1549712ab doc/daily-psk: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 6737c291ca doc/collect-wireless-mac: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse b9b1197c1a doc/check-routeros-update: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse a2afb1d5dc doc/check-lte-firmware-upgrade: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse f68ee9bc00 doc/check-health: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 71ce8709ca doc/check-certificates: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 0c46668e2e doc/certificate-renew-issued: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 50694ec512 doc/capsman-rolling-upgrade: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 9deaed7350 doc/capsman-download-packages: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse a92715ea31 doc/backup-upload: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse acc8cdf8ca doc/backup-partition: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 7b527840b1 doc/backup-email: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 4af1092272 doc/backup-cloud: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse f9fb61ec49 doc/accesslist-duplicates: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 13d0075a48 INITIAL-COMMANDS: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 120d4780fd CONTRIBUTIONS: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse 4f3cf3656c BRANCHES: add badges 2024-03-12 15:27:15 +01:00
Christian Hesse d46156ad92 global-functions: use variable name $ScriptName 2024-03-12 15:27:14 +01:00
Christian Hesse 771ca341b0 Merge branch 'main-function' into next 2024-03-04 21:40:34 +01:00
Christian Hesse 698360f037 update-tunnelbroker: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse ad623f069e update-gre-address: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 6fd745fc0f telegram-chat: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 6b1c6a7119 sms-forward: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 721b6c783b sms-action: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse d6077025b2 ppp-on-up: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 492edb4263 packages-update: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 09ea05d989 ospf-to-leds: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 3c76738915 netwatch-notify: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 458fd1fdcd netwatch-dns: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 400516295e mode-button: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 50e1c45880 log-forward: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 49650d8b14 lease-script: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse d6ea66ccd3 ipv6-update: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 85dbe3a868 ipsec-to-dns: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse a36ec397d6 hotspot-to-wpa: move code into function 2024-03-04 21:40:34 +01:00
Christian Hesse 2bf02cf085 hotspot-to-wpa-cleanup: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse a0fc6c30ef gps-track: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 480ad0c196 fw-addr-lists: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse cf986caf8d firmware-upgrade-reboot: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 29f544d18d dhcp-to-dns: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 82ec11f2fc dhcp-lease-comment: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 31da6b8bd5 daily-psk: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse e2b87c8634 collect-wireless-mac: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 22eb74cb3a check-routeros-update: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 450ea2fa48 check-lte-firmware-upgrade: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 80180b432d check-health: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse fc3fad5e87 check-certificates: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 2d112c0b33 certificate-renew-issued: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 4cbf9fab74 capsman-rolling-upgrade: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse c2df671d6f capsman-download-packages: move code into function 2024-03-04 17:04:45 +01:00
Christian Hesse 1c26dde356 backup-upload: move code into function 2024-03-04 16:34:01 +01:00
Christian Hesse 0ded98c9e2 backup-partition: move code into function 2024-03-04 16:33:57 +01:00
Christian Hesse 19fb7b61ea backup-email: move code into function 2024-03-04 16:33:54 +01:00
Christian Hesse 33d129496c backup-cloud: move code into function 2024-03-04 16:33:51 +01:00
Christian Hesse efc2e75f01 accesslist-duplicates: move code into function 2024-03-04 16:33:45 +01:00
Christian Hesse 64aa6ef124 netwatch-notify: check one after another
This can bring an extra delay, but saves a check in most cases.
2024-03-03 20:32:23 +01:00
Christian Hesse 4869d74edf netwatch-notify: handle IPv6 / AAAA resolving 2024-03-02 22:08:40 +01:00
Christian Hesse 50a6914907 netwatch-notify: (mis-)use firewall address-list for lookup...
... and drop the racy code querying dns cache. 😁
2024-03-01 12:30:18 +01:00
Christian Hesse 20d1ad17d7 Merge branch 'fw-addr-lists' into next 2024-02-29 14:22:07 +01:00
Christian Hesse 62790ae091 fw-addr-lists: add support for IPv6 2024-02-29 14:21:58 +01:00
Christian Hesse 0125f102b4 fw-addr-lists: rename variable 2024-02-29 14:21:58 +01:00
Christian Hesse 31966479dc fw-addr-lists: update wording 2024-02-29 14:21:58 +01:00
Christian Hesse 1687e2780f fw-addr-lists: get timeout from loop 2024-02-29 14:21:58 +01:00
Christian Hesse b9e0ffac1d Merge branch 'netwatch-notify' into next 2024-02-29 14:21:46 +01:00
Christian Hesse a924de274c netwatch-notify: handle CNAME to multiple records 2024-02-28 23:01:43 +01:00
Christian Hesse 6f29c640e4 netwatch-notify: move check in DNS cache to local function 2024-02-28 23:01:43 +01:00
Christian Hesse 01d2c3ea7e netwatch-notify: try another workaround
The last one did not make it... Perhaps the cache just needs
a moment to settle?
2024-02-28 23:01:43 +01:00
Christian Hesse 93bed1b081 netwatch-notify: work around race condition
This used to crash every now and then with:

> script;error script error: no such item (4)

I guess this is caused by querying the dns cache just exactly when a
record expires. The chance is maximized: The script is started by
scheduler every minute, and the record's ttl is a multiple of a minute.

Let's query records that are not about to expire immediately, and
try again.
2024-02-28 23:01:43 +01:00
Christian Hesse c2f5272f18 netwatch-notify: restore the check 🥴
This reverts commit 28da1da49e.

Chances are that we have to resolve a CNAME, that does not match when
querying the cache.

How to handle CNAME do multiple A records? 🤨
2024-02-28 23:01:43 +01:00
Christian Hesse 45875ad68e netwatch-notify: simplify the check 2024-02-28 23:01:43 +01:00
Christian Hesse b1199ca50a netwatch-notify: ... and switch state to "unknown" on host update 2024-02-28 23:01:43 +01:00
Christian Hesse 1344694708 netwatch-notify: handle status "down" in its own condition...
... instead of else-branch.

This makes sure to skip hosts that just became "unknown".
(Possible soon!)
2024-02-28 23:01:43 +01:00
Christian Hesse 1c2048628d netwatch-notify: use logical operator, no literal "and"
Just like we do everywhere else.
2024-02-28 23:01:43 +01:00
Christian Hesse 471e0ead05 doc/netwatch-notify: update for multiple records 2024-02-28 23:01:00 +01:00
132 changed files with 4288 additions and 4060 deletions

View file

@ -1,6 +1,13 @@
Installing from branches 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) [⬅️ Go back to main README](README.md)
> ⚠️ **Warning**: Living on the edge? Great, read on! > ⚠️ **Warning**: Living on the edge? Great, read on!

View file

@ -1,6 +1,13 @@
Past Contributions Past Contributions
================== ==================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](README.md)
Thanks a lot for your contributions! ❤️ Thanks a lot for your contributions! ❤️

View file

@ -1,6 +1,13 @@
Initial commands Initial commands
================ ================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](README.md)
> ⚠️ **Warning**: These command are inteneded for initial setup. If you are > ⚠️ **Warning**: These command are inteneded for initial setup. If you are

View file

@ -5,39 +5,32 @@
CAPSMAN = $(wildcard *.capsman.rsc) CAPSMAN = $(wildcard *.capsman.rsc)
LOCAL = $(wildcard *.local.rsc) LOCAL = $(wildcard *.local.rsc)
WIFI = $(wildcard *.wifi.rsc) WIFI = $(wildcard *.wifi.rsc)
WIFIWAVE2 = $(wildcard *.wifiwave2.rsc)
MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md)
HTML = $(MARKDOWN:.md=.html) HTML = $(MARKDOWN:.md=.html)
all: $(CAPSMAN) $(LOCAL) $(WIFI) $(WIFIWAVE2) $(HTML) all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML)
%.html: %.md Makefile %.html: %.md Makefile
markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@ markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@
%.capsman.rsc: %.template.rsc Makefile %.capsman.rsc: %.template.rsc Makefile
sed -e '/\/interface\/wifi\//d' -e '/\/interface\/wifiwave2\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.capsman|' \ sed -e '/\/interface\/wifi\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.capsman|' \
-e '/^# NOT \/caps-man\/ #$$/,/^# NOT \/caps-man\/ #$$/d' \ -e '/^# NOT \/caps-man\/ #$$/,/^# NOT \/caps-man\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@ < $< > $@
%.local.rsc: %.template.rsc Makefile %.local.rsc: %.template.rsc Makefile
sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e '/\/interface\/wifiwave2\//d' -e 's|%TEMPL%|.local|' \ sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e 's|%TEMPL%|.local|' \
-e '/^# NOT \/interface\/wireless\/ #$$/,/^# NOT \/interface\/wireless\/ #$$/d' \ -e '/^# NOT \/interface\/wireless\/ #$$/,/^# NOT \/interface\/wireless\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@ < $< > $@
%.wifi.rsc: %.template.rsc Makefile %.wifi.rsc: %.template.rsc Makefile
sed -e '/\/caps-man\//d' -e '/\/interface\/wifiwave2\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifi|' \ sed -e '/\/caps-man\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifi|' \
-e '/^# NOT \/interface\/wifi\/ #$$/,/^# NOT \/interface\/wifi\/ #$$/d' \ -e '/^# NOT \/interface\/wifi\/ #$$/,/^# NOT \/interface\/wifi\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \ -e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@ < $< > $@
%.wifiwave2.rsc: %.template.rsc Makefile
sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifiwave2|' \
-e '/^# NOT \/interface\/wifiwave2\/ #$$/,/^# NOT \/interface\/wifiwave2\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@
clean: clean:
rm -f $(HTML) rm -f $(HTML)

View file

@ -139,6 +139,11 @@ Save changes and exit with `Ctrl-o`.
![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif) ![screenshot: edit global-config-overlay](README.d/07-edit-global-config-overlay.avif)
Additionally creating configuration snippets is supported. The script name
of these snippets has to start with `global-config-overlay.d/` to make them
being loaded automatically. This allows to split off parts of the
configuration.
To apply your changes run `global-config`, which will automatically load To apply your changes run `global-config`, which will automatically load
the overlay as well: the overlay as well:

View file

@ -10,22 +10,25 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local Seen ({}); :do {
:local ScriptName [ :jobname ];
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen ({});
: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={ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:put ("Removing numeric id " . $Remove . "...\n"); :local Mac [ /caps-man/access-list/get $AccList mac-address ];
/caps-man/access-list/remove $Remove; :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;
} }
:set ($Seen->$Mac) 1; } on-error={ }
}

View file

@ -10,22 +10,25 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local Seen ({}); :do {
:local ScriptName [ :jobname ];
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen ({});
: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={ :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:put ("Removing numeric id " . $Remove . "...\n"); :local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
/interface/wireless/access-list/remove $Remove; :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;
} }
:set ($Seen->$Mac) 1; } on-error={ }
}

View file

@ -11,34 +11,33 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local Seen ({}); :do {
:local ScriptName [ :jobname ];
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen ({});
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:foreach AccList in=[ /interface/wifiwave2/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/wifiwave2/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/wifiwave2/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={ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:put ("Removing numeric id " . $Remove . "...\n"); :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
/caps-man/access-list/remove $Remove; :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
/interface/wifi/access-list/remove $Remove; :local Mac [ /caps-man/access-list/get $AccList mac-address ];
/interface/wifiwave2/access-list/remove $Remove; :local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
/interface/wireless/access-list/remove $Remove; :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;
} }
:set ($Seen->$Mac) 1; } on-error={ }
}

View file

@ -10,22 +10,25 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local Seen ({}); :do {
:local ScriptName [ :jobname ];
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :local Seen ({});
: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={ :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:put ("Removing numeric id " . $Remove . "...\n"); :local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
/interface/wifi/access-list/remove $Remove; :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;
} }
:set ($Seen->$Mac) 1; } on-error={ }
}

View file

@ -1,31 +0,0 @@
#!rsc by RouterOS
# RouterOS script: accesslist-duplicates.wifiwave2
# 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!
:local 0 [ :jobname ];
:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local Seen ({});
:foreach AccList in=[ /interface/wifiwave2/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /interface/wifiwave2/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={
/interface/wifiwave2/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/wifiwave2/access-list/remove $Remove;
}
}
:set ($Seen->$Mac) 1;
}

View file

@ -9,55 +9,77 @@
# upload backup to MikroTik cloud # upload backup to MikroTik cloud
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-cloud.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global BackupPassword;
:global BackupRandomDelay;
:global Identity;
:global DeviceInfo;
:global FormatLine;
:global HumanReadableNum;
:global LogPrintExit2;
:global RandomDelay;
:global ScriptFromTerminal;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global WaitFullyConnected;
$ScriptLock $0;
$WaitFullyConnected;
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
$RandomDelay $BackupRandomDelay;
}
:do { :do {
# we are not interested in output, but print is :local ScriptName [ :jobname ];
# 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; \ :global BackupRandomDelay;
subject=([ $SymbolForNotification "floppy-disk,cloud" ] . "Cloud backup"); \ :global Identity;
message=("Uploaded backup for " . $Identity . " to cloud.\n\n" . \ :global PackagesUpdateBackupFailure;
[ $DeviceInfo ] . "\n\n" . \
[ $FormatLine "Name" ($Cloud->"name") ] . "\n" . \ :global DeviceInfo;
[ $FormatLine "Size" ([ $HumanReadableNum ($Cloud->"size") 1024 ] . "iB") ] . "\n" . \ :global FormatLine;
[ $FormatLine "Download key" ($Cloud->"secret-download-key") ]); silent=true }); :global HumanReadableNum;
} on-error={ :global LogPrint;
$SendNotification2 ({ origin=$0; \ :global MkDir;
subject=([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Cloud backup failed"); \ :global RandomDelay;
message=("Failed uploading backup for " . $Identity . " to cloud!\n\n" . [ $DeviceInfo ]) }); :global ScriptFromTerminal;
$LogPrintExit2 error $0 ("Failed uploading backup for " . $Identity . " to cloud!") true; :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={ }

View file

@ -9,104 +9,116 @@
# create and email backup and config file # create and email backup and config file
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-email.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global BackupPassword; :do {
:global BackupRandomDelay; :local ScriptName [ :jobname ];
:global BackupSendBinary;
:global BackupSendExport;
:global BackupSendGlobalConfig;
:global Domain;
:global Identity;
:global CleanName; :global BackupPassword;
:global DeviceInfo; :global BackupRandomDelay;
:global FormatLine; :global BackupSendBinary;
:global LogPrintExit2; :global BackupSendExport;
:global MkDir; :global BackupSendGlobalConfig;
:global RandomDelay; :global Domain;
:global ScriptFromTerminal; :global Identity;
:global ScriptLock; :global PackagesUpdateBackupFailure;
:global SendEMail2;
:global SymbolForNotification;
:global WaitForFile;
:global WaitFullyConnected;
:if ([ :typeof $SendEMail2 ] = "nothing") do={ :global CleanName;
$LogPrintExit2 error $0 ("The module for sending notifications via e-mail is not installed.") true; :global DeviceInfo;
} :global FormatLine;
:global LogPrint;
:global MkDir;
:global RandomDelay;
:global ScriptFromTerminal;
:global ScriptLock;
:global SendEMail2;
:global SymbolForNotification;
:global WaitForFile;
:global WaitFullyConnected;
:if ($BackupSendBinary != true && \ :if ([ :typeof $SendEMail2 ] = "nothing") do={
$BackupSendExport != true) do={ $LogPrint error $ScriptName ("The module for sending notifications via e-mail is not installed.");
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true; :error false;
}
$ScriptLock $0;
$WaitFullyConnected;
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
$RandomDelay $BackupRandomDelay;
}
# filename based on identity
:local DirName ("tmpfs/" . $0);
: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={
$LogPrintExit2 error $0 ("Failed creating directory!") true;
}
# binary backup
:if ($BackupSendBinary = true) do={
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
$WaitForFile ($FilePath . ".backup");
:set BackupFile ($FileName . ".backup");
:set Attach ($Attach, ($FilePath . ".backup"));
}
# create configuration export
:if ($BackupSendExport = true) do={
/export terse show-sensitive file=$FilePath;
$WaitForFile ($FilePath . ".rsc");
:set ExportFile ($FileName . ".rsc");
:set Attach ($Attach, ($FilePath . ".rsc"));
}
# global-config-overlay
:if ($BackupSendGlobalConfig = true) do={
# 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=$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" . \
[ $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={
$LogPrintExit2 warning $0 ("Files are still available, sending e-mail failed.") true;
} }
:delay 1s;
:set I ($I + 1); :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={ }

View file

@ -9,37 +9,49 @@
# save configuration to fallback partition # save configuration to fallback partition
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-partition.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2;
:global ScriptLock;
$ScriptLock $0;
: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 FallbackTo [ /partitions/get $ActiveRunning fallback-to ];
:do { :do {
/system/scheduler/add start-time=startup name="running-from-backup-partition" \ :local ScriptName [ :jobname ];
on-event=(":log warning (\"Running from partition '\" . " . \
"[ /partitions/get [ find where running ] name ] . \"'!\")"); :global PackagesUpdateBackupFailure;
/partitions/save-config-to $FallbackTo;
/system/scheduler/remove "running-from-backup-partition"; :global LogPrint;
$LogPrintExit2 info $0 ("Saved configuration to partition '" . \ :global ScriptLock;
$FallbackTo . "'.") false;
} on-error={ :if ([ $ScriptLock $ScriptName ] = false) do={
/system/scheduler/remove [ find where name="running-from-backup-partition" ]; :set PackagesUpdateBackupFailure true;
$LogPrintExit2 error $0 ("Failed saving configuration to partition '" . \ :error false;
$FallbackTo . "'!") true; }
}
: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={ }

View file

@ -9,143 +9,153 @@
# create and upload backup and config file # create and upload backup and config file
# https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/backup-upload.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global BackupPassword; :do {
:global BackupRandomDelay; :local ScriptName [ :jobname ];
:global BackupSendBinary;
:global BackupSendExport;
:global BackupSendGlobalConfig;
:global BackupUploadPass;
:global BackupUploadUrl;
:global BackupUploadUser;
:global Domain;
:global Identity;
:global CleanName; :global BackupPassword;
:global DeviceInfo; :global BackupRandomDelay;
:global IfThenElse; :global BackupSendBinary;
:global LogPrintExit2; :global BackupSendExport;
:global MkDir; :global BackupSendGlobalConfig;
:global RandomDelay; :global BackupUploadPass;
:global ScriptFromTerminal; :global BackupUploadUrl;
:global ScriptLock; :global BackupUploadUser;
:global SendNotification2; :global Domain;
:global SymbolForNotification; :global Identity;
:global WaitForFile; :global PackagesUpdateBackupFailure;
:global WaitFullyConnected;
:if ($BackupSendBinary != true && \ :global CleanName;
$BackupSendExport != true) do={ :global DeviceInfo;
$LogPrintExit2 error $0 ("Configured to send neither backup nor config export.") true;
}
$ScriptLock $0;
$WaitFullyConnected;
:if ([ $ScriptFromTerminal $0 ] = false && $BackupRandomDelay > 0) do={
$RandomDelay $BackupRandomDelay;
}
# filename based on identity
:local DirName ("tmpfs/" . $0);
: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={
$LogPrintExit2 error $0 ("Failed creating directory!") true;
}
# binary backup
:if ($BackupSendBinary = true) do={
/system/backup/save encryption=aes-sha256 name=$FilePath password=$BackupPassword;
$WaitForFile ($FilePath . ".backup");
:do {
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".backup") \
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".backup");
:set BackupFile [ /file/get ($FilePath . ".backup") ];
:set ($BackupFile->"name") ($FileName . ".backup");
} on-error={
$LogPrintExit2 error $0 ("Uploading backup file failed!") false;
:set BackupFile "failed";
:set Failed 1;
}
/file/remove ($FilePath . ".backup");
}
# create configuration export
:if ($BackupSendExport = true) do={
/export terse show-sensitive file=$FilePath;
$WaitForFile ($FilePath . ".rsc");
:do {
/tool/fetch upload=yes url=($BackupUploadUrl . "/" . $FileName . ".rsc") \
user=$BackupUploadUser password=$BackupUploadPass src-path=($FilePath . ".rsc");
:set ExportFile [ /file/get ($FilePath . ".rsc") ];
:set ($ExportFile->"name") ($FileName . ".rsc");
} on-error={
$LogPrintExit2 error $0 ("Uploading configuration export failed!") false;
:set ExportFile "failed";
:set Failed 1;
}
/file/remove ($FilePath . ".rsc");
}
# global-config-overlay
:if ($BackupSendGlobalConfig = true) do={
# 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={
$LogPrintExit2 error $0 ("Uploading global-config-overlay failed!") false;
: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; :global IfThenElse;
:global LogPrint;
:global MkDir;
:global RandomDelay;
:global ScriptFromTerminal;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global WaitForFile;
:global WaitFullyConnected;
:return \ :if ($BackupSendBinary != true && \
[ $IfThenElse ([ :typeof $File ] = "array") \ $BackupSendExport != true) do={
($Name . ":\n" . [ $FormatLine " name" ($File->"name") ] . "\n" . \ $LogPrint error $ScriptName ("Configured to send neither backup nor config export.");
[ $FormatLine " size" ([ $HumanReadableNum ($File->"size") 1024 ] . "iB") ]) \ :error false;
[ $FormatLine $Name $File ] ]; }
}
$SendNotification2 ({ origin=$0; \ :if ([ $ScriptLock $ScriptName ] = false) do={
subject=[ $IfThenElse ($Failed > 0) \ :set PackagesUpdateBackupFailure true;
([ $SymbolForNotification "floppy-disk,warning-sign" ] . "Backup & Config upload with failure") \ :error false;
([ $SymbolForNotification "floppy-disk,arrow-up" ] . "Backup & Config upload") ]; \ }
message=("Backup and config export upload for " . $Identity . ".\n\n" . \ $WaitFullyConnected;
[ $DeviceInfo ] . "\n\n" . \
[ $FileInfo "Backup file" $BackupFile ] . "\n" . \
[ $FileInfo "Export file" $ExportFile ] . "\n" . \
[ $FileInfo "Config file" $ConfigFile ]); silent=true });
:if ($Failed = 1) do={ :if ([ $ScriptFromTerminal $ScriptName ] = false && $BackupRandomDelay > 0) do={
:error "An error occured!"; $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={ }

View file

@ -11,66 +11,73 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CleanFilePath; :do {
:global DownloadPackage; :local ScriptName [ :jobname ];
:global LogPrintExit2;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
$ScriptLock $0; :global CleanFilePath;
$WaitFullyConnected; :global DownloadPackage;
:global LogPrint;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:local InstalledVersion [ /system/package/update/get installed-version ]; :error false;
: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 . \ $WaitFullyConnected;
"). Please place your packages!") false;
}
:foreach Package in=[ /file/find where type=package \ :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ];
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local InstalledVersion [ /system/package/update/get installed-version ];
:local File [ /file/get $Package ]; :local Updated false;
: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={ :if ([ :len $PackagePath ] = 0) do={
$LogPrintExit2 info $0 ("No packages available, downloading default set.") false; $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.");
:foreach Arch in={ "arm"; "mipsbe" } do={ :error false;
:foreach Package in={ "routeros"; "wireless" } do={ }
:if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={
:set Updated true; :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={ :if ($Updated = true) do={
:local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0);
:if ([ :len $Script ] > 0) do={ :if ([ :len $Script ] > 0) do={
/system/script/run $Script; /system/script/run $Script;
} else={ } else={
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
}
} }
} } on-error={ }

View file

@ -12,85 +12,83 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CleanFilePath; :do {
:global DownloadPackage; :local ScriptName [ :jobname ];
:global LogPrintExit2;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
$ScriptLock $0; :global CleanFilePath;
$WaitFullyConnected; :global DownloadPackage;
:global LogPrint;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
:local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; :error false;
:local PackagePath [ $CleanFilePath [ /interface/wifiwave2/capsman/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 . \ $WaitFullyConnected;
"). Please place your packages!") false;
}
:foreach Package in=[ /file/find where type=package \ :local PackagePath [ $CleanFilePath [ /caps-man/manager/get package-path ] ];
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ];
:local File [ /file/get $Package ]; :local InstalledVersion [ /system/package/update/get installed-version ];
:if ($File->"package-architecture" = "mips") do={ :local Updated false;
: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={ :if ([ :len $PackagePath ] = 0) do={
$LogPrintExit2 info $0 ("No packages available, downloading default set.") false; $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/ # # NOT /interface/wifi/ #
# NOT /interface/wifiwave2/ # :foreach Arch in={ "arm"; "mipsbe" } do={
:foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={
:foreach Package in={ "routeros"; "wireless" } do={
# NOT /interface/wifi/ # # NOT /interface/wifi/ #
# NOT /interface/wifiwave2/ #
# NOT /caps-man/ # # NOT /caps-man/ #
:foreach Arch in={ "arm"; "arm64" } do={ :foreach Arch in={ "arm"; "arm64" } do={
# NOT /interface/wifi/ # :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" };
:foreach Package in={ "routeros"; "wifiwave2" } do={ "arm64"={ "routeros"; "wifi-qcom" } };
# NOT /interface/wifi/ # :foreach Package in=($Packages->$Arch) do={
# NOT /interface/wifiwave2/ #
:local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" };
"arm64"={ "routeros"; "wifi-qcom" } };
:foreach Package in=($Packages->$Arch) do={
# NOT /interface/wifiwave2/ #
# NOT /caps-man/ # # NOT /caps-man/ #
:if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ :if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={
:set Updated true; :set Updated true;
}
} }
} }
} }
}
:if ($Updated = true) do={ :if ($Updated = true) do={
:local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0);
:if ([ :len $Script ] > 0) do={ :if ([ :len $Script ] > 0) do={
/system/script/run $Script; /system/script/run $Script;
} else={ } else={
/caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ]; /caps-man/remote-cap/upgrade [ find where version!=$InstalledVersion ];
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
/interface/wifiwave2/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; }
} }
} } on-error={ }

View file

@ -11,68 +11,75 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CleanFilePath; :do {
:global DownloadPackage; :local ScriptName [ :jobname ];
:global LogPrintExit2;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
$ScriptLock $0; :global CleanFilePath;
$WaitFullyConnected; :global DownloadPackage;
:global LogPrint;
:global MkDir;
:global ScriptLock;
:global WaitFullyConnected;
:local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:local InstalledVersion [ /system/package/update/get installed-version ]; :error false;
: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 . \ $WaitFullyConnected;
"). Please place your packages!") false;
}
:foreach Package in=[ /file/find where type=package \ :local PackagePath [ $CleanFilePath [ /interface/wifi/capsman/get package-path ] ];
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ :local InstalledVersion [ /system/package/update/get installed-version ];
:local File [ /file/get $Package ]; :local Updated false;
: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={ :if ([ :len $PackagePath ] = 0) do={
$LogPrintExit2 info $0 ("No packages available, downloading default set.") false; $LogPrint warning $ScriptName ("The CAPsMAN package path is not defined, can not download packages.");
:foreach Arch in={ "arm"; "arm64" } do={ :error false;
:local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; }
"arm64"={ "routeros"; "wifi-qcom" } };
:foreach Package in=($Packages->$Arch) do={ :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={
:if ([ $DownloadPackage $Package $InstalledVersion $Arch $PackagePath ] = true) do={ :if ([ $MkDir $PackagePath ] = false) do={
:set Updated true; $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={ :if ($Updated = true) do={
:local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0); :local Script ([ /system/script/find where source~"\n# provides: capsman-rolling-upgrade\n" ]->0);
:if ([ :len $Script ] > 0) do={ :if ([ :len $Script ] > 0) do={
/system/script/run $Script; /system/script/run $Script;
} else={ } else={
/interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ]; /interface/wifi/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
}
} }
} } on-error={ }

View file

@ -1,76 +0,0 @@
#!rsc by RouterOS
# RouterOS script: capsman-download-packages.wifiwave2
# 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!
:local 0 [ :jobname ];
: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 [ /interface/wifiwave2/capsman/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 [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
$LogPrintExit2 info $0 ("No packages available, downloading default set.") false;
:foreach Arch in={ "arm"; "arm64" } do={
:foreach Package in={ "routeros"; "wifiwave2" } 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/wifiwave2/capsman/remote-cap/upgrade [ find where version!=$InstalledVersion ];
}
}

View file

@ -12,30 +12,35 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:local InstalledVersion [ /system/package/update/get installed-version ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:error false;
: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");
} }
}
: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={ }

View file

@ -13,41 +13,42 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:local InstalledVersion [ /system/package/update/get installed-version ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:error false;
:local RemoteCapCount [ :len [ /caps-man/remote-cap/find ] ];
:local RemoteCapCount [ :len [ /interface/wifi/capsman/remote-cap/find ] ];
:local RemoteCapCount [ :len [ /interface/wifiwave2/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={
:foreach RemoteCap in=[ /interface/wifiwave2/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 ];
:local RemoteCapVal [ /interface/wifiwave2/capsman/remote-cap/get $RemoteCap ];
:if ([ :len $RemoteCapVal ] > 1) do={
# NOT /caps-man/ #
:set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name");
# NOT /caps-man/ #
$LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \
" (" . $RemoteCapVal->"identity" . ")...") false;
/caps-man/remote-cap/upgrade $RemoteCap;
/interface/wifi/capsman/remote-cap/upgrade $RemoteCap;
/interface/wifiwave2/capsman/remote-cap/upgrade $RemoteCap;
} else={
$LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false;
}
:delay ($Delay . "s");
} }
}
: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={ }

View file

@ -12,31 +12,36 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:local InstalledVersion [ /system/package/update/get installed-version ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:error false;
: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");
$LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \
" (" . $RemoteCapVal->"identity" . ")...") false;
/interface/wifi/capsman/remote-cap/upgrade $RemoteCap;
} else={
$LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false;
}
:delay ($Delay . "s");
} }
}
: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={ }

View file

@ -1,42 +0,0 @@
#!rsc by RouterOS
# RouterOS script: capsman-rolling-upgrade.wifiwave2
# 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!
:local 0 [ :jobname ];
: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 [ /interface/wifiwave2/capsman/remote-cap/find ] ];
:if ($RemoteCapCount > 0) do={
:local Delay (600 / $RemoteCapCount);
:if ($Delay > 120) do={ :set Delay 120; }
:foreach RemoteCap in=[ /interface/wifiwave2/capsman/remote-cap/find where version!=$InstalledVersion ] do={
:local RemoteCapVal [ /interface/wifiwave2/capsman/remote-cap/get $RemoteCap ];
:if ([ :len $RemoteCapVal ] > 1) do={
:set ($RemoteCapVal->"name") ($RemoteCapVal->"common-name");
$LogPrintExit2 info $0 ("Starting upgrade for " . $RemoteCapVal->"name" . \
" (" . $RemoteCapVal->"identity" . ")...") false;
/interface/wifiwave2/capsman/remote-cap/upgrade $RemoteCap;
} else={
$LogPrintExit2 warning $0 ("Remote CAP vanished, skipping upgrade.") false;
}
:delay ($Delay . "s");
}
}

View file

@ -8,36 +8,41 @@
# renew locally issued certificates # renew locally issued certificates
# https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/certificate-renew-issued.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CertIssuedExportPass; :do {
:local ScriptName [ :jobname ];
:global LogPrintExit2; :global CertIssuedExportPass;
:global MkDir;
:global ScriptLock;
$ScriptLock $0; :global LogPrint;
:global MkDir;
:global ScriptLock;
:foreach Cert in=[ /certificate/find where issued expires-after<3w ] do={ :if ([ $ScriptLock $ScriptName ] = false) do={
:local CertVal [ /certificate/get $Cert ]; :error false;
/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;
} }
}
: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={ }

View file

@ -8,202 +8,214 @@
# check for certificate validity # check for certificate validity
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-certificates.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CertRenewTime; :do {
:global CertRenewUrl; :local ScriptName [ :jobname ];
:global CertWarnTime;
:global Identity;
:global CertificateAvailable
:global EscapeForRegEx;
:global IfThenElse;
:global LogPrintExit2;
:global ParseKeyValueStore;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitFullyConnected;
:local CheckCertificatesDownloadImport do={
:local Name [ :tostr $1 ];
:global CertRenewTime;
:global CertRenewUrl; :global CertRenewUrl;
:global CertRenewPass; :global CertWarnTime;
:global Identity;
:global CertificateNameByCN; :global CertificateAvailable
:global EscapeForRegEx; :global EscapeForRegEx;
:global FetchUserAgent;
:global LogPrintExit2;
: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=({ $FetchUserAgent }) \
($CertRenewUrl . $CertFileName) dst-path=$CertFileName as-value;
$WaitForFile $CertFileName;
:local DecryptionFailed true;
:foreach PassPhrase in=$CertRenewPass do={
:local Result [ /certificate/import file-name=$CertFileName passphrase=$PassPhrase as-value ];
:if ($Result->"decryption-failures" = 0) do={
:set DecryptionFailed false;
}
}
/file/remove [ find where name=$CertFileName ];
:if ($DecryptionFailed = true) do={
$LogPrintExit2 warning $0 ("Decryption failed for certificate file '" . $CertFileName . "'.") false;
}
:foreach CertInChain in=[ /certificate/find where name~("^" . [ $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={
$LogPrintExit2 debug $0 ("Could not download certificate file '" . $CertFileName . "'.") false;
}
}
:return $Return;
}
:local FormatInfo do={
:local Cert $1;
:global FormatLine;
:global FormatMultiLines;
:global IfThenElse; :global IfThenElse;
:global LogPrint;
:global ParseKeyValueStore;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitFullyConnected;
:local FormatExpire do={ :local CheckCertificatesDownloadImport do={
:global CharacterReplace; :local Name [ :tostr $1 ];
:return [ $CharacterReplace [ $CharacterReplace [ :tostr $1 ] "w" "w " ] "d" "d " ];
:global CertRenewUrl;
:global CertRenewPass;
:global CertificateNameByCN;
:global EscapeForRegEx;
:global FetchUserAgent;
: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=({ $FetchUserAgent }) \
($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 $0 ("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 $0 ("Could not download certificate file '" . $CertFileName . "'.");
}
}
:return $Return;
} }
:local FormatCertChain do={ :local FormatInfo do={
:local Cert $1; :local Cert $1;
:global EitherOr; :global FormatLine;
:global ParseKeyValueStore; :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 ]; :local CertVal [ /certificate/get $Cert ];
:local Return "";
:for I from=0 to=5 do={ :return ( \
:set Return ($Return . [ $EitherOr ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") \ [ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \
([ $ParseKeyValueStore (($CertVal->"issuer")->0) ]->"CN") ]); [ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \
:set CertVal [ /certificate/get [ find where skid=($CertVal->"akid") ] ]; [ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \
:if (($CertVal->"akid") = "" || ($CertVal->"akid") = ($CertVal->"skid")) do={ [ $FormatLine "Private key" [ $IfThenElse (($CertVal->"private-key") = true) "available" "missing" ] ] . "\n" . \
:return $Return; [ $FormatLine "Fingerprint" ($CertVal->"fingerprint") ] . "\n" . \
} [ $IfThenElse ([ :len ($CertVal->"ca") ] > 0) [ $FormatLine "Issuer" ($CertVal->"ca") ] [ $FormatLine "Issuer chain" [ $FormatCertChain $Cert ] ] ] . "\n" . \
:set Return ($Return . " -> "); "Validity:\n" . \
} [ $FormatLine " from" ($CertVal->"invalid-before") ] . "\n" . \
:return ($Return . "..."); [ $FormatLine " to" ($CertVal->"invalid-after") ] . "\n" . \
[ $FormatLine "Expires in" [ $IfThenElse (($CertVal->"expired") = true) "expired" [ $FormatExpire ($CertVal->"expires-after") ] ] ]);
} }
:local CertVal [ /certificate/get $Cert ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:error false;
}
$WaitFullyConnected;
:return ( \ :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={
[ $FormatLine "Name" ($CertVal->"name") ] . "\n" . \ :local CertVal [ /certificate/get $Cert ];
[ $IfThenElse ([ :len ($CertVal->"common-name") ] > 0) ([ $FormatLine "CommonName" ($CertVal->"common-name") ] . "\n") ] . \ :local CertNew;
[ $IfThenElse ([ :len ($CertVal->"subject-alt-name") ] > 0) ([ $FormatMultiLines "SubjectAltNames" ($CertVal->"subject-alt-name") ] . "\n") ] . \ :local LastName;
[ $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") ] ] ]);
}
$ScriptLock $0; :do {
$WaitFullyConnected; :if ([ :len $CertRenewUrl ] = 0) do={
$LogPrint info $ScriptName ("No CertRenewUrl given.");
:foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expires-after<$CertRenewTime ] do={ :error false;
:local CertVal [ /certificate/get $Cert ];
:local CertNew;
:local LastName;
:do {
:if ([ :len $CertRenewUrl ] = 0) do={
$LogPrintExit2 info $0 ("No CertRenewUrl given.") true;
}
$LogPrintExit2 info $0 ("Attempting to renew certificate '" . ($CertVal->"name") . "'.") false;
:local ImportSuccess false;
:set LastName ($CertVal->"common-name");
:set ImportSuccess [ $CheckCertificatesDownloadImport $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 $LastName ];
} }
} $LogPrint info $ScriptName ("Attempting to renew certificate '" . ($CertVal->"name") . "'.");
:if ([ :len ($CertVal->"fingerprint") ] > 0 && $CertVal->"fingerprint" != [ /certificate/get $Cert fingerprint ]) do={ :local ImportSuccess false;
$LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was updated in place.") false; :set LastName ($CertVal->"common-name");
:set CertVal [ /certificate/get $Cert ]; :set ImportSuccess [ $CheckCertificatesDownloadImport $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 $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={ } else={
$LogPrintExit2 debug $0 ("Certificate '" . $CertVal->"name" . "' was not updated, but replaced.") false; :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ];
:set CertNew [ /certificate/find where name~("^" . [ $EscapeForRegEx [ $UrlEncode $LastName ] ] . "\\.(p12|pem)_[0-9]+\$") \ $SendNotification2 ({ origin=$ScriptName; \
(common-name=($CertVal->"common-name") or subject-alt-name~("(^|\\W)(DNS|IP):" . [ $EscapeForRegEx $LastName ] . "(\\W|\$)")) \ subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \
fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) });
:local CertNewVal [ /certificate/get $CertNew ]; $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \
", it is invalid after " . ($CertVal->"invalid-after") . ".");
:if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={
$LogPrintExit2 warning $0 ("The certificate chain is not available!") 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");
:set CertNewVal;
:set CertVal [ /certificate/get $CertNew ];
} }
$SendNotification2 ({ origin=$0; silent=true; \
subject=([ $SymbolForNotification "lock-with-ink-pen" ] . "Certificate renewed: " . ($CertVal->"name")); \
message=("A certificate on " . $Identity . " has been renewed.\n\n" . [ $FormatInfo $CertNew ]) });
$LogPrintExit2 info $0 ("The certificate '" . ($CertVal->"name") . "' has been renewed.") false;
} on-error={
$LogPrintExit2 debug $0 ("Could not renew certificate '" . ($CertVal->"name") . "'.") false;
} }
} } on-error={ }
:foreach Cert in=[ /certificate/find where !revoked !scep-url !(expires-after=[]) \
expires-after<$CertWarnTime !(fingerprint=[]) ] do={
:local CertVal [ /certificate/get $Cert ];
:if ([ :len [ /certificate/scep-server/find where ca-cert=($CertVal->"ca") ] ] > 0) do={
$LogPrintExit2 debug $0 ("Certificate '" . ($CertVal->"name") . "' is handled by SCEP, skipping.") false;
} else={
:local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ];
$SendNotification2 ({ origin=$0; \
subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \
message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) });
$LogPrintExit2 info $0 ("The certificate '" . ($CertVal->"name") . "' " . $State . \
", it is invalid after " . ($CertVal->"invalid-after") . ".") false;
}
}

View file

@ -8,165 +8,171 @@
# check for RouterOS health state # check for RouterOS health state
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-health.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global CheckHealthCPUUtilization; :do {
:global CheckHealthCPUUtilizationNotified; :local ScriptName [ :jobname ];
:global CheckHealthLast;
:global CheckHealthRAMUtilizationNotified;
:global CheckHealthTemperature;
:global CheckHealthTemperatureDeviation;
:global CheckHealthTemperatureNotified;
:global CheckHealthVoltageLow;
:global CheckHealthVoltagePercent;
:global Identity;
:global FormatLine; :global CheckHealthCPUUtilization;
:global HumanReadableNum; :global CheckHealthCPUUtilizationNotified;
:global IfThenElse; :global CheckHealthLast;
:global LogPrintExit2; :global CheckHealthRAMUtilizationNotified;
:global ScriptLock; :global CheckHealthTemperature;
:global SendNotification2; :global CheckHealthTemperatureDeviation;
:global SymbolForNotification; :global CheckHealthTemperatureNotified;
:global CheckHealthVoltageLow;
:global CheckHealthVoltagePercent;
:global Identity;
:local TempToNum do={ :global FormatLine;
:global CharacterReplace; :global HumanReadableNum;
:local T [ :toarray [ $CharacterReplace $1 "." "," ] ]; :global IfThenElse;
:return ($T->0 * 10 + $T->1); :global LogPrint;
} :global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0; :local TempToNum do={
:global CharacterReplace;
:local T [ :toarray [ $CharacterReplace $1 "." "," ] ];
:return ($T->0 * 10 + $T->1);
}
:local Resource [ /system/resource/get ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:error false;
}
:set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5); :local Resource [ /system/resource/get ];
:if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={
$SendNotification2 ({ origin=$0; \
subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \
message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") });
:set CheckHealthCPUUtilizationNotified true;
}
:if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={
$SendNotification2 ({ origin=$0; \
subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \
message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") });
:set CheckHealthCPUUtilizationNotified false;
}
:local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory"); :set CheckHealthCPUUtilization (($CheckHealthCPUUtilization * 4 + ($Resource->"cpu-load") * 10) / 5);
:if ($CheckHealthRAMUtilization >=80 && $CheckHealthRAMUtilizationNotified != true) do={ :if ($CheckHealthCPUUtilization > 750 && $CheckHealthCPUUtilizationNotified != true) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "card-file-box,chart-increasing" ] . "Health warning: RAM utilization"); \ subject=([ $SymbolForNotification "abacus,chart-increasing" ] . "Health warning: CPU utilization"); \
message=("The RAM utilization on " . $Identity . " is at " . $CheckHealthRAMUtilization . "%!\n\n" . \ message=("The average CPU utilization on " . $Identity . " is at " . ($CheckHealthCPUUtilization / 10) . "%!") });
[ $FormatLine "total" ([ $HumanReadableNum ($Resource->"total-memory") 1024 ] . "iB") 8 ] . "\n" . \ :set CheckHealthCPUUtilizationNotified true;
[ $FormatLine "used" ([ $HumanReadableNum ($Resource->"total-memory" - $Resource->"free-memory") 1024 ] . "iB") 8 ] . "\n" . \ }
[ $FormatLine "free" ([ $HumanReadableNum ($Resource->"free-memory") 1024 ] . "iB") 8 ]) }); :if ($CheckHealthCPUUtilization < 650 && $CheckHealthCPUUtilizationNotified = true) do={
:set CheckHealthRAMUtilizationNotified true; $SendNotification2 ({ origin=$ScriptName; \
} subject=([ $SymbolForNotification "abacus,chart-decreasing" ] . "Health recovery: CPU utilization"); \
:if ($CheckHealthRAMUtilization < 70 && $CheckHealthRAMUtilizationNotified = true) do={ message=("The average CPU utilization on " . $Identity . " decreased to " . ($CheckHealthCPUUtilization / 10) . "%.") });
$SendNotification2 ({ origin=$0; \ :set CheckHealthCPUUtilizationNotified false;
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={ :local CheckHealthRAMUtilization (($Resource->"total-memory" - $Resource->"free-memory") * 100 / $Resource->"total-memory");
$LogPrintExit2 debug $0 ("Your device does not provide any health values.") true; :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 ([ :typeof $CheckHealthLast ] != "array") do={ :if ([ :len [ /system/health/find ] ] = 0) do={
:set CheckHealthLast ({}); $LogPrint debug $ScriptName ("Your device does not provide any health values.");
} :error true;
:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={ }
:set CheckHealthTemperatureNotified ({});
} :if ([ :typeof $CheckHealthLast ] != "array") do={
:set CheckHealthLast ({});
}
:if ([ :typeof $CheckHealthTemperatureNotified ] != "array") do={
:set CheckHealthTemperatureNotified ({});
}
:foreach Voltage in=[ /system/health/find where type="V" ] do={ :foreach Voltage in=[ /system/health/find where type="V" ] do={
:local Name [ /system/health/get $Voltage name ]; :local Name [ /system/health/get $Voltage name ];
:local Value [ /system/health/get $Voltage value ]; :local Value [ /system/health/get $Voltage value ];
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
:local NumCurr [ $TempToNum $Value ]; :local NumCurr [ $TempToNum $Value ];
:local NumLast [ $TempToNum ($CheckHealthLast->$Name) ]; :local NumLast [ $TempToNum ($CheckHealthLast->$Name) ];
:if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \
$NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \
$NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \
message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \
[ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \ [ $FormatLine "old value" ($CheckHealthLast->$Name . " V") 12 ] . "\n" . \
[ $FormatLine "new value" ($Value . " V") 12 ]) }); [ $FormatLine "new value" ($Value . " V") 12 ]) });
} else={ } else={
:if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \
message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") });
} }
:if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \
message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") });
}
} }
} }
:set ($CheckHealthLast->$Name) $Value;
} }
:set ($CheckHealthLast->$Name) $Value;
}
:foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={ :foreach PSU in=[ /system/health/find where name~"^psu.*-state\$" ] do={
:local Name [ /system/health/get $PSU name ]; :local Name [ /system/health/get $PSU name ];
:local Value [ /system/health/get $PSU value ]; :local Value [ /system/health/get $PSU value ];
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
:if ($CheckHealthLast->$Name = "ok" && \ :if ($CheckHealthLast->$Name = "ok" && \
$Value != "ok") do={ $Value != "ok") do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \
message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") }); message=("The power supply unit '" . $Name . "' on " . $Identity . " failed!") });
} }
:if ($CheckHealthLast->$Name != "ok" && \ :if ($CheckHealthLast->$Name != "ok" && \
$Value = "ok") do={ $Value = "ok") do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") }); message=("The power supply unit '" . $Name . "' on " . $Identity . " recovered!") });
}
} }
:set ($CheckHealthLast->$Name) $Value;
} }
:set ($CheckHealthLast->$Name) $Value;
}
:foreach Temperature in=[ /system/health/find where type="C" ] do={ :foreach Temperature in=[ /system/health/find where type="C" ] do={
:local Name [ /system/health/get $Temperature name ]; :local Name [ /system/health/get $Temperature name ];
:local Value [ /system/health/get $Temperature value ]; :local Value [ /system/health/get $Temperature value ];
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
:if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={ :if ([ :typeof ($CheckHealthTemperature->$Name) ] != "num" ) do={
$LogPrintExit2 info $0 ("No threshold given for " . $Name . ", assuming 50C.") false; $LogPrint info $ScriptName ("No threshold given for " . $Name . ", assuming 50C.");
:set ($CheckHealthTemperature->$Name) 50; :set ($CheckHealthTemperature->$Name) 50;
} }
:local Validate [ /system/health/get [ find where name=$Name ] value ]; :local Validate [ /system/health/get [ find where name=$Name ] value ];
:while ($Value != $Validate) do={ :while ($Value != $Validate) do={
:set Value $Validate; :set Value $Validate;
:set Validate [ /system/health/get [ find where name=$Name ] value ]; :set Validate [ /system/health/get [ find where name=$Name ] value ];
} }
:if ($Value > $CheckHealthTemperature->$Name && \ :if ($Value > $CheckHealthTemperature->$Name && \
$CheckHealthTemperatureNotified->$Name != true) do={ $CheckHealthTemperatureNotified->$Name != true) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \
message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ message=("The " . $Name . " on " . $Identity . " is above threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0" . "C") });
:set ($CheckHealthTemperatureNotified->$Name) true; :set ($CheckHealthTemperatureNotified->$Name) true;
} }
:if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \
$CheckHealthTemperatureNotified->$Name = true) do={ $CheckHealthTemperatureNotified->$Name = true) do={
$SendNotification2 ({ origin=$0; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0" . "C") });
:set ($CheckHealthTemperatureNotified->$Name) false; :set ($CheckHealthTemperatureNotified->$Name) false;
}
} }
:set ($CheckHealthLast->$Name) $Value;
} }
:set ($CheckHealthLast->$Name) $Value; } on-error={ }
}

View file

@ -8,91 +8,96 @@
# check for LTE firmware upgrade, send notification # check for LTE firmware upgrade, send notification
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-lte-firmware-upgrade.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global SentLteFirmwareUpgradeNotification; :do {
:local ScriptName [ :jobname ];
:global ScriptLock;
$ScriptLock $0;
:if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={
:global SentLteFirmwareUpgradeNotification ({});
}
:local CheckInterface do={
:local ScriptName $1;
:local Interface $2;
:global Identity;
:global SentLteFirmwareUpgradeNotification; :global SentLteFirmwareUpgradeNotification;
:global FormatLine; :global ScriptLock;
:global IfThenElse;
:global LogPrintExit2;
:global ScriptFromTerminal;
:global SendNotification2;
:global SymbolForNotification;
:local IntName [ /interface/lte/get $Interface name ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:local Firmware; :error false;
: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 ([ :len ($Firmware->"latest") ] = 0) do={ :if ([ :typeof $SentLteFirmwareUpgradeNotification ] != "array") do={
$LogPrintExit2 info $0 ("An empty string is not a valid version.") false; :global SentLteFirmwareUpgradeNotification ({});
:return false;
} }
:if (($Firmware->"installed") = ($Firmware->"latest")) do={ :local CheckInterface do={
:if ([ $ScriptFromTerminal $ScriptName ] = true) do={ :local ScriptName $1;
$LogPrintExit2 info $0 ("No firmware upgrade available for LTE interface " . $IntName . ".") false; :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;
} }
:return true;
}
:if ([ $ScriptFromTerminal $ScriptName ] = true && \ :if ([ :len ($Firmware->"latest") ] = 0) do={
[ :len [ /system/script/find where name="unattended-lte-firmware-upgrade" ] ] > 0) do={ $LogPrint info $ScriptName ("An empty string is not a valid version.");
:put ("Do you want to start unattended lte firmware upgrade for interface " . $IntName . "? [y/N]"); :return false;
: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; :if (($Firmware->"installed") = ($Firmware->"latest")) do={
:if ([ $ScriptFromTerminal $ScriptName ] = true) do={
$LogPrint info $ScriptName ("No firmware upgrade available for LTE interface " . $IntName . ".");
}
:return true; :return true;
} else={
:put "Canceled...";
} }
: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");
} }
:if (($SentLteFirmwareUpgradeNotification->$IntName) = ($Firmware->"latest")) do={ :foreach Interface in=[ /interface/lte/find ] do={
$LogPrintExit2 debug $0 ("Already sent the LTE firmware upgrade notification for version " . \ $CheckInterface $ScriptName $Interface;
($Firmware->"latest") . ".") false;
:return false;
} }
} on-error={ }
$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" . \
[ $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 $0 $Interface;
}

View file

@ -8,149 +8,157 @@
# check for RouterOS update, send notification and/or install # check for RouterOS update, send notification and/or install
# https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/check-routeros-update.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity; :do {
:global SafeUpdateAll; :local ScriptName [ :jobname ];
:global SafeUpdateNeighbor;
:global SafeUpdateNeighborIdentity;
:global SafeUpdatePatch;
:global SafeUpdateUrl;
:global SentRouterosUpdateNotification;
:global DeviceInfo; :global Identity;
:global EscapeForRegEx; :global SafeUpdateAll;
:global LogPrintExit2; :global SafeUpdateNeighbor;
:global ScriptFromTerminal; :global SafeUpdateNeighborIdentity;
:global ScriptLock; :global SafeUpdatePatch;
:global SendNotification2; :global SafeUpdateUrl;
:global SymbolForNotification; :global SentRouterosUpdateNotification;
:global VersionToNum;
:global WaitFullyConnected;
:local DoUpdate do={ :global DeviceInfo;
:if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={ :global EscapeForRegEx;
/system/script/run packages-update; :global LogPrint;
} else={ :global ScriptFromTerminal;
/system/package/update/install without-paging; :global ScriptLock;
} :global SendNotification2;
:error "Waiting for system to reboot."; :global SymbolForNotification;
} :global VersionToNum;
:global WaitFullyConnected;
$ScriptLock $0; :local DoUpdate do={
:if ([ :len [ /system/script/find where name="packages-update" ] ] > 0) do={
$WaitFullyConnected; /system/script/run packages-update;
} else={
:if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ /system/package/update/install without-paging;
:error "A reboot for update is already scheduled."; }
} :error "Waiting for system to reboot.";
$LogPrintExit2 debug $0 ("Checking for updates...") false;
/system/package/update/check-for-updates without-paging as-value;
:local Update [ /system/package/update/get ];
:if ([ $ScriptFromTerminal $0 ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={
$LogPrintExit2 info $0 ("System is already up to date.") true;
}
:local NumInstalled [ $VersionToNum ($Update->"installed-version") ];
:local NumLatest [ $VersionToNum ($Update->"latest-version") ];
:local Link ("https://mikrotik.com/download/changelogs/" . $Update->"channel" . "-release-tree");
:if ($NumLatest < 117505792) do={
$LogPrintExit2 info $0 ("The version '" . ($Update->"latest-version") . "' is not a valid version.") true;
}
:if ($NumInstalled < $NumLatest) do={
:if ($SafeUpdateAll ~ "^YES,? ?PLEASE!?\$") do={
$LogPrintExit2 info $0 ("Installing ALL versions automatically, including " . \
$Update->"latest-version" . "...") false;
$SendNotification2 ({ origin=$0; \
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $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={ :if ([ $ScriptLock $ScriptName ] = false) do={
$LogPrintExit2 info $0 ("Version " . $Update->"latest-version" . " is a patch release, updating...") false; :error false;
$SendNotification2 ({ origin=$0; \ }
subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \ $WaitFullyConnected;
message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \
", updating on " . $Identity . "..."); link=$Link; silent=true }); :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={
$DoUpdate; :error "A reboot for update is already scheduled.";
} }
:if ($SafeUpdateNeighbor = true) do={ $LogPrint debug $ScriptName ("Checking for updates...");
:local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \ /system/package/update/check-for-updates without-paging as-value;
version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ]; :local Update [ /system/package/update/get ];
:if ([ :len $Neighbors ] > 0) do={
:local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ]; :if ([ $ScriptFromTerminal $ScriptName ] = true && ($Update->"installed-version") = ($Update->"latest-version")) do={
$LogPrintExit2 info $0 ("Seen a neighbor (" . $Neighbor . ") running version " . \ $LogPrint info $ScriptName ("System is already up to date.");
$Update->"latest-version" . " from " . $Update->"channel" . ", updating...") false; :error true;
$SendNotification2 ({ origin=$0; \ }
: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"); \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \
message=("Seen a neighbor (" . $Neighbor . ") running version " . $Update->"latest-version" . \ message=("Installing ALL versions automatically, including " . $Update->"latest-version" . \
" from " . $Update->"channel" . ", updating on " . $Identity . "..."); link=$Link; silent=true }); "... Updating on " . $Identity . "..."); link=$Link; silent=true });
$DoUpdate; $DoUpdate;
} }
}
:if ([ :len $SafeUpdateUrl ] > 0) do={ :if ($SafeUpdatePatch = true && ($NumInstalled & 0xffff0000) = ($NumLatest & 0xffff0000)) do={
:local Result; $LogPrint info $ScriptName ("Version " . $Update->"latest-version" . " is a patch release, updating...");
:do { $SendNotification2 ({ origin=$ScriptName; \
: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: " . $Update->"latest-version"); \ subject=([ $SymbolForNotification "sparkles" ] . "RouterOS update: " . $Update->"latest-version"); \
message=("Version " . $Update->"latest-version" . " is considered safe for " . $Update->"channel" . \ message=("Version " . $Update->"latest-version" . " is a patch update for " . $Update->"channel" . \
", updating on " . $Identity . "..."); link=$Link; silent=true }); ", updating on " . $Identity . "..."); link=$Link; silent=true });
$DoUpdate; $DoUpdate;
} }
}
:if ([ $ScriptFromTerminal $0 ] = true) do={ :if ($SafeUpdateNeighbor = true) do={
:put ("Do you want to install RouterOS version " . $Update->"latest-version" . "? [y/N]"); :local Neighbors [ /ip/neighbor/find where platform="MikroTik" identity~$SafeUpdateNeighborIdentity \
:if (([ /terminal/inkey timeout=60 ] % 32) = 25) do={ version~("^" . [ $EscapeForRegEx ($Update->"latest-version") ] . "\\b") ];
$DoUpdate; :if ([ :len $Neighbors ] > 0) do={
} else={ :local Neighbor [ /ip/neighbor/get ($Neighbors->0) identity ];
:put "Canceled..."; $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") 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 ($SentRouterosUpdateNotification = $Update->"latest-version") do={ :if ($NumInstalled > $NumLatest) do={
$LogPrintExit2 info $0 ("Already sent the RouterOS update notification for version " . \ :if ($SentRouterosUpdateNotification = $Update->"latest-version") do={
$Update->"latest-version" . ".") true; $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={ }
$SendNotification2 ({ origin=$0; \
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={
$LogPrintExit2 info $0 ("Already sent the RouterOS downgrade notification for version " . \
$Update->"latest-version" . ".") true;
}
$SendNotification2 ({ origin=$0; \
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 });
$LogPrintExit2 info $0 ("A different RouterOS version " . ($Update->"latest-version") . \
" is available for downgrade.") false;
:set SentRouterosUpdateNotification ($Update->"latest-version");
}

View file

@ -11,81 +11,86 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity; :do {
:local ScriptName [ :jobname ];
:global EitherOr; :global Identity;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0 false 10; :global EitherOr;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ $ScriptLock $ScriptName 10 ] = false) do={
/caps-man/access-list/add comment="--- collected above ---" disabled=yes; :error false;
$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={ :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); /caps-man/access-list/add comment="--- collected above ---" disabled=yes;
:if ([ :len $AccessList ] > 0) do={ $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.");
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ }
[ /caps-man/access-list/get $AccessList comment ]) 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={
$LogPrint debug $ScriptName ("Device already gone... Ignoring.");
} }
:if ([ :len $AccessList ] = 0) do={ :if ([ :len ($RegVal->"mac-address") ] > 0) do={
:local Address "no dhcp lease"; :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local DnsName "no dhcp lease"; :if ([ :len $AccessList ] > 0) do={
:local HostName "no dhcp lease"; $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \
:local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); [ /caps-man/access-list/get $AccessList comment ]);
: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" ]; :if ([ :len $AccessList ] = 0) do={
:set DnsName "no dns name"; :local Address "no dhcp lease";
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :local DnsName "no dhcp lease";
:if ([ :len $DnsRec ] > 0) do={ :local HostName "no dhcp lease";
:set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
:foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :if ([ :len $Lease ] > 0) do={
:set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); :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 ]) });
} }
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); } else={
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; $LogPrint debug $ScriptName ("No mac address available... Ignoring.");
: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" . \
[ $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={
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
} }
} } on-error={ }

View file

@ -11,82 +11,87 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity; :do {
:local ScriptName [ :jobname ];
:global EitherOr; :global Identity;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0 false 10; :global EitherOr;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ $ScriptLock $ScriptName 10 ] = false) do={
/interface/wireless/access-list/add comment="--- collected above ---" disabled=yes; :error false;
$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 where ap=no ] 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={ :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes;
:if ([ :len $AccessList ] > 0) do={ $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.");
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ }
[ /interface/wireless/access-list/get $AccessList comment ]) false; :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 $AccessList ] = 0) do={ :if ([ :len ($RegVal->"mac-address") ] > 0) do={
:local Address "no dhcp lease"; :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local DnsName "no dhcp lease"; :if ([ :len $AccessList ] > 0) do={
:local HostName "no dhcp lease"; $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \
:local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); [ /interface/wireless/access-list/get $AccessList comment ]);
: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" ]; :if ([ :len $AccessList ] = 0) do={
:set DnsName "no dns name"; :local Address "no dhcp lease";
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :local DnsName "no dhcp lease";
:if ([ :len $DnsRec ] > 0) do={ :local HostName "no dhcp lease";
:set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
:foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :if ([ :len $Lease ] > 0) do={
:set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); :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 ]) });
} }
:set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; } else={
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); $LogPrint debug $ScriptName ("No mac address available... Ignoring.");
: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" . \
[ $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={
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
} }
} } on-error={ }

View file

@ -12,106 +12,103 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity; :do {
:local ScriptName [ :jobname ];
:global EitherOr; :global Identity;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0 false 10; :global EitherOr;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ $ScriptLock $ScriptName 10 ] = false) do={
:if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :error false;
:if ([ :len [ /interface/wifiwave2/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/wifiwave2/access-list/add comment="--- collected above ---" disabled=yes;
/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 ([ /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/wifiwave2/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/wifiwave2/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/wifiwave2/registration-table/get $Reg ];
: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={ :if ([ :len [ /caps-man/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); :if ([ :len [ /interface/wireless/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /interface/wifiwave2/access-list/find where mac-address=($RegVal->"mac-address") ]->0); /caps-man/access-list/add comment="--- collected above ---" disabled=yes;
:local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0); /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes;
:if ([ :len $AccessList ] > 0) do={ /interface/wireless/access-list/add comment="--- collected above ---" disabled=yes;
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.");
[ /caps-man/access-list/get $AccessList comment ]) false; }
[ /interface/wifi/access-list/get $AccessList comment ]) false; :local PlaceBefore ([ /caps-man/access-list/find where comment="--- collected above ---" disabled ]->0);
[ /interface/wifiwave2/access-list/get $AccessList comment ]) false; :local PlaceBefore ([ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ]->0);
[ /interface/wireless/access-list/get $AccessList comment ]) false; :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 $AccessList ] = 0) do={ :if ([ :len ($RegVal->"mac-address") ] > 0) do={
:local Address "no dhcp lease"; :local AccessList ([ /caps-man/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local DnsName "no dhcp lease"; :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local HostName "no dhcp lease"; :local AccessList ([ /interface/wireless/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); :if ([ :len $AccessList ] > 0) do={
:if ([ :len $Lease ] > 0) do={ $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \
:set Address [ /ip/dhcp-server/lease/get $Lease active-address ]; [ /caps-man/access-list/get $AccessList comment ]);
:set HostName [ $EitherOr [ /ip/dhcp-server/lease/get $Lease host-name ] "no hostname" ]; [ /interface/wifi/access-list/get $AccessList comment ]);
:set DnsName "no dns name"; [ /interface/wireless/access-list/get $AccessList comment ]);
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); }
:if ([ :len $DnsRec ] > 0) do={
:set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); :if ([ :len $AccessList ] = 0) do={
:foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :local Address "no dhcp lease";
:set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); :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 ]) });
} }
:set ($RegVal->"ssid") [ /interface/wireless/get [ find where name=($RegVal->"interface") ] ssid ]; } else={
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); $LogPrint debug $ScriptName ("No mac address available... Ignoring.");
: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;
/interface/wifi/access-list/add place-before=$PlaceBefore comment=$Message mac-address=($RegVal->"mac-address") disabled=yes;
/interface/wifiwave2/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=$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" . \
[ $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={
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
} }
} } on-error={ }

View file

@ -11,81 +11,86 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity; :do {
:local ScriptName [ :jobname ];
:global EitherOr; :global Identity;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0 false 10; :global EitherOr;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={ :if ([ $ScriptLock $ScriptName 10 ] = false) do={
/interface/wifi/access-list/add comment="--- collected above ---" disabled=yes; :error false;
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
}
: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={
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
} }
:if ([ :len ($RegVal->"mac-address") ] > 0) do={ :if ([ :len [ /interface/wifi/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
:local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0); /interface/wifi/access-list/add comment="--- collected above ---" disabled=yes;
:if ([ :len $AccessList ] > 0) do={ $LogPrint warning $ScriptName ("Added disabled access-list entry with comment '--- collected above ---'.");
$LogPrintExit2 debug $0 ("MAC address " . $RegVal->"mac-address" . " already known: " . \ }
[ /interface/wifi/access-list/get $AccessList comment ]) false; :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 $AccessList ] = 0) do={ :if ([ :len ($RegVal->"mac-address") ] > 0) do={
:local Address "no dhcp lease"; :local AccessList ([ /interface/wifi/access-list/find where mac-address=($RegVal->"mac-address") ]->0);
:local DnsName "no dhcp lease"; :if ([ :len $AccessList ] > 0) do={
:local HostName "no dhcp lease"; $LogPrint debug $ScriptName ("MAC address " . $RegVal->"mac-address" . " already known: " . \
:local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0); [ /interface/wifi/access-list/get $AccessList comment ]);
: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" ]; :if ([ :len $AccessList ] = 0) do={
:set DnsName "no dns name"; :local Address "no dhcp lease";
:local DnsRec ([ /ip/dns/static/find where address=$Address ]->0); :local DnsName "no dhcp lease";
:if ([ :len $DnsRec ] > 0) do={ :local HostName "no dhcp lease";
:set DnsName ({ [ /ip/dns/static/get $DnsRec name ] }); :local Lease ([ /ip/dhcp-server/lease/find where active-mac-address=($RegVal->"mac-address") dynamic=yes status=bound ]->0);
:foreach CName in=[ /ip/dns/static/find where type=CNAME cname=($DnsName->0) ] do={ :if ([ :len $Lease ] > 0) do={
:set DnsName ($DnsName, [ /ip/dns/static/get $CName name ]); :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 ]) });
} }
:local DateTime ([ /system/clock/get date ] . " " . [ /system/clock/get time ]); } else={
:local Vendor [ $GetMacVendor ($RegVal->"mac-address") ]; $LogPrint debug $ScriptName ("No mac address available... Ignoring.");
: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/wifi/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" . \
[ $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={
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
} }
} } on-error={ }

View file

@ -1,91 +0,0 @@
#!rsc by RouterOS
# RouterOS script: collect-wireless-mac.wifiwave2
# 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!
:local 0 [ :jobname ];
:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Identity;
:global EitherOr;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
$ScriptLock $0 false 10;
:if ([ :len [ /interface/wifiwave2/access-list/find where comment="--- collected above ---" disabled ] ] = 0) do={
/interface/wifiwave2/access-list/add comment="--- collected above ---" disabled=yes;
$LogPrintExit2 warning $0 ("Added disabled access-list entry with comment '--- collected above ---'.") false;
}
:local PlaceBefore ([ /interface/wifiwave2/access-list/find where comment="--- collected above ---" disabled ]->0);
:foreach Reg in=[ /interface/wifiwave2/registration-table/find ] do={
:local RegVal;
:do {
:set RegVal [ /interface/wifiwave2/registration-table/get $Reg ];
} on-error={
$LogPrintExit2 debug $0 ("Device already gone... Ignoring.") false;
}
:if ([ :len ($RegVal->"mac-address") ] > 0) do={
:local AccessList ([ /interface/wifiwave2/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/wifiwave2/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 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");
$LogPrintExit2 info $0 $Message false;
/interface/wifiwave2/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" . \
[ $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={
$LogPrintExit2 debug $0 ("No mac address available... Ignoring.") false;
}
}

View file

@ -11,77 +11,82 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global DailyPskMatchComment; :do {
:global DailyPskQrCodeUrl; :local ScriptName [ :jobname ];
:global Identity;
:global FormatLine; :global DailyPskMatchComment;
:global LogPrintExit2; :global DailyPskQrCodeUrl;
:global ScriptLock; :global Identity;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
$ScriptLock $0; :global FormatLine;
$WaitFullyConnected; :global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
# return pseudo-random string for PSK :if ([ $ScriptLock $ScriptName ] = false) do={
:local GeneratePSK do={ :error false;
:local Date [ :tostr $1 ]; }
$WaitFullyConnected;
:global DailyPskSecrets; # return pseudo-random string for PSK
:local GeneratePSK do={
:local Date [ :tostr $1 ];
:global ParseDate; :global DailyPskSecrets;
:set Date [ $ParseDate $Date ]; :global ParseDate;
:local A ((14 - ($Date->"month")) / 12); :set Date [ $ParseDate $Date ];
: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)) . \ :local A ((14 - ($Date->"month")) / 12);
($DailyPskSecrets->1->(($Date->"month") - 1)) . \ :local B (($Date->"year") - $A);
($DailyPskSecrets->2->$WeekDay)); :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));
:local Seen ({}); :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \
:local Date [ /system/clock/get date ]; ($DailyPskSecrets->1->(($Date->"month") - 1)) . \
:local NewPsk [ $GeneratePSK $Date ]; ($DailyPskSecrets->2->$WeekDay));
}
:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ :local Seen ({});
:local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ]; :local Date [ /system/clock/get date ];
:local Configuration ([ /caps-man/configuration/find where ssid~$SsidRegExp ]->0); :local NewPsk [ $GeneratePSK $Date ];
: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={ :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ];
/caps-man/access-list/set $AccList private-passphrase=$NewPsk; :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 ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ($NewPsk != $OldPsk) do={
:if ($Seen->$Ssid = 1) do={ $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")");
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; /caps-man/access-list/set $AccList private-passphrase=$NewPsk;
} else={
:local Link ($DailyPskQrCodeUrl . \ :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); :if ($Seen->$Ssid = 1) do={
$SendNotification2 ({ origin=$0; \ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.");
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ } else={
message=("This is the daily PSK on " . $Identity . ":\n\n" . \ :local Link ($DailyPskQrCodeUrl . \
[ $FormatLine "SSID" $Ssid ] . "\n" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
[ $FormatLine "PSK" $NewPsk ] . "\n" . \ $SendNotification2 ({ origin=$ScriptName; \
[ $FormatLine "Date" $Date ] . "\n\n" . \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
"A client device specific rule must not exist!"); link=$Link }); message=("This is the daily PSK on " . $Identity . ":\n\n" . \
:set ($Seen->$Ssid) 1; [ $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={ }

View file

@ -11,76 +11,81 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global DailyPskMatchComment; :do {
:global DailyPskQrCodeUrl; :local ScriptName [ :jobname ];
:global Identity;
:global FormatLine; :global DailyPskMatchComment;
:global LogPrintExit2; :global DailyPskQrCodeUrl;
:global ScriptLock; :global Identity;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
$ScriptLock $0; :global FormatLine;
$WaitFullyConnected; :global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
# return pseudo-random string for PSK :if ([ $ScriptLock $ScriptName ] = false) do={
:local GeneratePSK do={ :error false;
:local Date [ :tostr $1 ]; }
$WaitFullyConnected;
:global DailyPskSecrets; # return pseudo-random string for PSK
:local GeneratePSK do={
:local Date [ :tostr $1 ];
:global ParseDate; :global DailyPskSecrets;
:set Date [ $ParseDate $Date ]; :global ParseDate;
:local A ((14 - ($Date->"month")) / 12); :set Date [ $ParseDate $Date ];
: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)) . \ :local A ((14 - ($Date->"month")) / 12);
($DailyPskSecrets->1->(($Date->"month") - 1)) . \ :local B (($Date->"year") - $A);
($DailyPskSecrets->2->$WeekDay)); :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));
:local Seen ({}); :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \
:local Date [ /system/clock/get date ]; ($DailyPskSecrets->1->(($Date->"month") - 1)) . \
:local NewPsk [ $GeneratePSK $Date ]; ($DailyPskSecrets->2->$WeekDay));
}
:foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={ :local Seen ({});
:local IntName [ /interface/wireless/access-list/get $AccList interface ]; :local Date [ /system/clock/get date ];
:local Ssid [ /interface/wireless/get $IntName ssid ]; :local NewPsk [ $GeneratePSK $Date ];
:local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ];
:local Skip 0;
:if ($NewPsk != $OldPsk) do={ :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; :local IntName [ /interface/wireless/access-list/get $AccList interface ];
/interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :local Ssid [ /interface/wireless/get $IntName ssid ];
:local OldPsk [ /interface/wireless/access-list/get $AccList private-pre-shared-key ];
:local Skip 0;
:if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ :if ($NewPsk != $OldPsk) do={
:if ($Seen->$Ssid = 1) do={ $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")");
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk;
} else={
:local Link ($DailyPskQrCodeUrl . \ :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); :if ($Seen->$Ssid = 1) do={
$SendNotification2 ({ origin=$0; \ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.");
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ } else={
message=("This is the daily PSK on " . $Identity . ":\n\n" . \ :local Link ($DailyPskQrCodeUrl . \
[ $FormatLine "SSID" $Ssid ] . "\n" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
[ $FormatLine "PSK" $NewPsk ] . "\n" . \ $SendNotification2 ({ origin=$ScriptName; \
[ $FormatLine "Date" $Date ] . "\n\n" . \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
"A client device specific rule must not exist!"); link=$Link }); message=("This is the daily PSK on " . $Identity . ":\n\n" . \
:set ($Seen->$Ssid) 1; [ $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={ }

View file

@ -12,98 +12,96 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global DailyPskMatchComment; :do {
:global DailyPskQrCodeUrl; :local ScriptName [ :jobname ];
:global Identity;
:global FormatLine; :global DailyPskMatchComment;
:global LogPrintExit2; :global DailyPskQrCodeUrl;
:global ScriptLock; :global Identity;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
$ScriptLock $0; :global FormatLine;
$WaitFullyConnected; :global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
# return pseudo-random string for PSK :if ([ $ScriptLock $ScriptName ] = false) do={
:local GeneratePSK do={ :error false;
:local Date [ :tostr $1 ]; }
$WaitFullyConnected;
:global DailyPskSecrets; # return pseudo-random string for PSK
:local GeneratePSK do={
:local Date [ :tostr $1 ];
:global ParseDate; :global DailyPskSecrets;
:set Date [ $ParseDate $Date ]; :global ParseDate;
:local A ((14 - ($Date->"month")) / 12); :set Date [ $ParseDate $Date ];
: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)) . \ :local A ((14 - ($Date->"month")) / 12);
($DailyPskSecrets->1->(($Date->"month") - 1)) . \ :local B (($Date->"year") - $A);
($DailyPskSecrets->2->$WeekDay)); :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));
:local Seen ({}); :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \
:local Date [ /system/clock/get date ]; ($DailyPskSecrets->1->(($Date->"month") - 1)) . \
:local NewPsk [ $GeneratePSK $Date ]; ($DailyPskSecrets->2->$WeekDay));
}
:foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={ :local Seen ({});
:foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ :local Date [ /system/clock/get date ];
:foreach AccList in=[ /interface/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={ :local NewPsk [ $GeneratePSK $Date ];
: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 SsidRegExp [ /interface/wifiwave2/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 Configuration ([ /interface/wifiwave2/configuration/find where ssid~$SsidRegExp ]->0);
:local Ssid [ /caps-man/configuration/get $Configuration ssid ];
:local Ssid [ /interface/wifi/configuration/get $Configuration ssid ];
:local Ssid [ /interface/wifiwave2/configuration/get $Configuration ssid ];
:local OldPsk [ /caps-man/access-list/get $AccList private-passphrase ];
:local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ];
:local OldPsk [ /interface/wifiwave2/access-list/get $AccList passphrase ];
# /caps-man/ /interface/wifi/ /interface/wifiwave2/ 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={ :foreach AccList in=[ /caps-man/access-list/find where comment~$DailyPskMatchComment ] do={
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={
/caps-man/access-list/set $AccList private-passphrase=$NewPsk; :foreach AccList in=[ /interface/wireless/access-list/find where comment~$DailyPskMatchComment ] do={
/interface/wifi/access-list/set $AccList passphrase=$NewPsk; :local SsidRegExp [ /caps-man/access-list/get $AccList ssid-regexp ];
/interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk; :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ];
/interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk; :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 ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={ :if ($NewPsk != $OldPsk) do={
:if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")");
:if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ /caps-man/access-list/set $AccList private-passphrase=$NewPsk;
:if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={ /interface/wifi/access-list/set $AccList passphrase=$NewPsk;
:if ($Seen->$Ssid = 1) do={ /interface/wireless/access-list/set $AccList private-pre-shared-key=$NewPsk;
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
} else={ :if ([ :len [ /caps-man/actual-interface-configuration/find where configuration.ssid=$Ssid !disabled ] ] > 0) do={
:local Link ($DailyPskQrCodeUrl . \ :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); :if ([ :len [ /interface/wireless/find where name=$IntName !disabled ] ] = 1) do={
$SendNotification2 ({ origin=$0; \ :if ($Seen->$Ssid = 1) do={
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.");
message=("This is the daily PSK on " . $Identity . ":\n\n" . \ } else={
[ $FormatLine "SSID" $Ssid ] . "\n" . \ :local Link ($DailyPskQrCodeUrl . \
[ $FormatLine "PSK" $NewPsk ] . "\n" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
[ $FormatLine "Date" $Date ] . "\n\n" . \ $SendNotification2 ({ origin=$ScriptName; \
"A client device specific rule must not exist!"); link=$Link }); subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
:set ($Seen->$Ssid) 1; 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={ }

View file

@ -11,77 +11,82 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global DailyPskMatchComment; :do {
:global DailyPskQrCodeUrl; :local ScriptName [ :jobname ];
:global Identity;
:global FormatLine; :global DailyPskMatchComment;
:global LogPrintExit2; :global DailyPskQrCodeUrl;
:global ScriptLock; :global Identity;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
$ScriptLock $0; :global FormatLine;
$WaitFullyConnected; :global LogPrint;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
# return pseudo-random string for PSK :if ([ $ScriptLock $ScriptName ] = false) do={
:local GeneratePSK do={ :error false;
:local Date [ :tostr $1 ]; }
$WaitFullyConnected;
:global DailyPskSecrets; # return pseudo-random string for PSK
:local GeneratePSK do={
:local Date [ :tostr $1 ];
:global ParseDate; :global DailyPskSecrets;
:set Date [ $ParseDate $Date ]; :global ParseDate;
:local A ((14 - ($Date->"month")) / 12); :set Date [ $ParseDate $Date ];
: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)) . \ :local A ((14 - ($Date->"month")) / 12);
($DailyPskSecrets->1->(($Date->"month") - 1)) . \ :local B (($Date->"year") - $A);
($DailyPskSecrets->2->$WeekDay)); :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));
:local Seen ({}); :return (($DailyPskSecrets->0->(($Date->"day") - 1)) . \
:local Date [ /system/clock/get date ]; ($DailyPskSecrets->1->(($Date->"month") - 1)) . \
:local NewPsk [ $GeneratePSK $Date ]; ($DailyPskSecrets->2->$WeekDay));
}
:foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={ :local Seen ({});
:local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ]; :local Date [ /system/clock/get date ];
:local Configuration ([ /interface/wifi/configuration/find where ssid~$SsidRegExp ]->0); :local NewPsk [ $GeneratePSK $Date ];
:local Ssid [ /interface/wifi/configuration/get $Configuration ssid ];
:local OldPsk [ /interface/wifi/access-list/get $AccList passphrase ];
:local Skip 0;
:if ($NewPsk != $OldPsk) do={ :foreach AccList in=[ /interface/wifi/access-list/find where comment~$DailyPskMatchComment ] do={
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false; :local SsidRegExp [ /interface/wifi/access-list/get $AccList ssid-regexp ];
/interface/wifi/access-list/set $AccList passphrase=$NewPsk; :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 ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={ :if ($NewPsk != $OldPsk) do={
:if ($Seen->$Ssid = 1) do={ $LogPrint info $ScriptName ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")");
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false; /interface/wifi/access-list/set $AccList passphrase=$NewPsk;
} else={
:local Link ($DailyPskQrCodeUrl . \ :if ([ :len [ /interface/wifi/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]); :if ($Seen->$Ssid = 1) do={
$SendNotification2 ({ origin=$0; \ $LogPrint debug $ScriptName ("Already sent a mail for SSID " . $Ssid . ", skipping.");
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \ } else={
message=("This is the daily PSK on " . $Identity . ":\n\n" . \ :local Link ($DailyPskQrCodeUrl . \
[ $FormatLine "SSID" $Ssid ] . "\n" . \ "?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
[ $FormatLine "PSK" $NewPsk ] . "\n" . \ $SendNotification2 ({ origin=$ScriptName; \
[ $FormatLine "Date" $Date ] . "\n\n" . \ subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
"A client device specific rule must not exist!"); link=$Link }); message=("This is the daily PSK on " . $Identity . ":\n\n" . \
:set ($Seen->$Ssid) 1; [ $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={ }

View file

@ -1,87 +0,0 @@
#!rsc by RouterOS
# RouterOS script: daily-psk.wifiwave2
# 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!
:local 0 [ :jobname ];
:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global DailyPskMatchComment;
:global DailyPskQrCodeUrl;
:global Identity;
:global FormatLine;
:global LogPrintExit2;
:global ScriptLock;
:global SendNotification2;
:global SymbolForNotification;
:global UrlEncode;
:global WaitForFile;
:global WaitFullyConnected;
$ScriptLock $0;
$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/wifiwave2/access-list/find where comment~$DailyPskMatchComment ] do={
:local SsidRegExp [ /interface/wifiwave2/access-list/get $AccList ssid-regexp ];
:local Configuration ([ /interface/wifiwave2/configuration/find where ssid~$SsidRegExp ]->0);
:local Ssid [ /interface/wifiwave2/configuration/get $Configuration ssid ];
:local OldPsk [ /interface/wifiwave2/access-list/get $AccList passphrase ];
:local Skip 0;
:if ($NewPsk != $OldPsk) do={
$LogPrintExit2 info $0 ("Updating daily PSK for " . $Ssid . " to " . $NewPsk . " (was " . $OldPsk . ")") false;
/interface/wifiwave2/access-list/set $AccList passphrase=$NewPsk;
:if ([ :len [ /interface/wifiwave2/actual-configuration/find where configuration.ssid=$Ssid ] ] > 0) do={
:if ($Seen->$Ssid = 1) do={
$LogPrintExit2 debug $0 ("Already sent a mail for SSID " . $Ssid . ", skipping.") false;
} else={
:local Link ($DailyPskQrCodeUrl . \
"?scale=8&level=1&ssid=" . [ $UrlEncode $Ssid ] . "&pass=" . [ $UrlEncode $NewPsk ]);
$SendNotification2 ({ origin=$0; \
subject=([ $SymbolForNotification "calendar" ] . "daily PSK " . $Ssid); \
message=("This is the daily PSK on " . $Identity . ":\n\n" . \
[ $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;
}
}
}
}

View file

@ -11,24 +11,29 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :if ([ $ScriptLock $ScriptName ] = false) do={
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :error false;
: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={
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
/ip/dhcp-server/lease/set comment=$NewComment $Lease; :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={ }

View file

@ -11,24 +11,29 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :if ([ $ScriptLock $ScriptName ] = false) do={
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :error false;
: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={
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
/ip/dhcp-server/lease/set comment=$NewComment $Lease; :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={ }

View file

@ -12,30 +12,33 @@
# !! This is just a template to generate the real script! # !! This is just a template to generate the real script!
# !! Pattern '%TEMPL%' is replaced, paths are filtered. # !! Pattern '%TEMPL%' is replaced, paths are filtered.
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :if ([ $ScriptLock $ScriptName ] = false) do={
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :error false;
: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/wifiwave2/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/wifiwave2/access-list/get $AccessList comment ];
: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->"active-mac-address" . ": " . $NewComment) false; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
/ip/dhcp-server/lease/set comment=$NewComment $Lease; :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={ }

View file

@ -11,24 +11,29 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={ :if ([ $ScriptLock $ScriptName ] = false) do={
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :error false;
: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={
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic=yes status=bound ] do={
/ip/dhcp-server/lease/set comment=$NewComment $Lease; :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={ }

View file

@ -1,34 +0,0 @@
#!rsc by RouterOS
# RouterOS script: dhcp-lease-comment.wifiwave2
# 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!
:local 0 [ :jobname ];
:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2;
:global ScriptLock;
$ScriptLock $0;
: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/wifiwave2/access-list/find where mac-address=($LeaseVal->"active-mac-address") ]->0);
:if ([ :len $AccessList ] > 0) do={
:set NewComment [ /interface/wifiwave2/access-list/get $AccessList comment ];
}
:if ([ :len $NewComment ] != 0 && $LeaseVal->"comment" != $NewComment) do={
$LogPrintExit2 info $0 ("Updating comment for DHCP lease " . $LeaseVal->"active-mac-address" . ": " . $NewComment) false;
/ip/dhcp-server/lease/set comment=$NewComment $Lease;
}
}

View file

@ -9,113 +9,118 @@
# check DHCP leases and add/remove/update DNS entries # check DHCP leases and add/remove/update DNS entries
# https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/dhcp-to-dns.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global Domain; :do {
:global Identity; :local ScriptName [ :jobname ];
:global CleanName; :global Domain;
:global EitherOr; :global Identity;
:global IfThenElse;
:global LogPrintExit2;
:global LogPrintOnce;
:global ParseKeyValueStore;
:global ScriptLock;
$ScriptLock $0 false 10; :global CleanName;
:global EitherOr;
:global IfThenElse;
:global LogPrint;
:global LogPrintOnce;
:global ParseKeyValueStore;
:global ScriptLock;
:local Ttl 5m; :if ([ $ScriptLock $ScriptName 10 ] = false) do={
:local CommentPrefix ("managed by " . $0); :error false;
:local CommentString ("--- " . $0 . " 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;
$LogPrintExit2 warning $0 ("Added disabled static dns record with name '" . $CommentString . "'.") false;
}
: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={
$LogPrintExit2 debug $0 ("Lease for " . $MacInServer . " (" . $DnsRecordVal->"name" . ") still exists. Not deleting record.") false;
} else={
:local Found false;
$LogPrintExit2 info $0 ("Lease expired for " . $MacInServer . ", deleting record (" . $DnsRecordVal->"name" . ").") false;
/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 $0 ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!") false;
}
} on-error={
$LogPrintExit2 debug $0 ("A lease just vanished, ignoring.") false;
} }
:if ([ :len ($LeaseVal->"active-address") ] > 0) do={ :local Ttl 5m;
:local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server"); :local CommentPrefix ("managed by " . $ScriptName);
:local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ]; :local CommentString ("--- " . $ScriptName . " above ---");
:local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ];
:local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ]; :if ([ :len [ /ip/dns/static/find where (name=$CommentString or (comment=$CommentString and name=-)) type=NXDOMAIN disabled ] ] = 0) do={
:local NetworkVal; /ip/dns/static/add name=$CommentString type=NXDOMAIN disabled=yes;
:if ([ :len $Network ] > 0) do={ $LogPrint warning $ScriptName ("Added disabled static dns record with name '" . $CommentString . "'.");
:set NetworkVal [ /ip/dhcp-server/network/get ($Network->0) ]; }
: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") ];
} }
: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) ]; :foreach Lease in=[ /ip/dhcp-server/lease/find where status=bound ] do={
:if ([ :len $DnsRecord ] > 0) do={ :local LeaseVal;
:local DnsRecordVal [ /ip/dns/static/get $DnsRecord ]; :do {
:set LeaseVal [ /ip/dhcp-server/lease/get $Lease ];
:if ($DnsRecordVal->"address" = $LeaseVal->"active-address" && $DnsRecordVal->"name" = $FullA) do={ :if ([ :len [ /ip/dhcp-server/lease/find where active-mac-address=($LeaseVal->"active-mac-address") status=bound ] ] > 1) do={
$LogPrintExit2 debug $0 ("The A record for " . $MacInServer . " (" . $FullA . ") does not need updating.") false; $LogPrintOnce info $ScriptName ("Multiple bound leases found for mac-address " . ($LeaseVal->"active-mac-address") . "!");
} else={
$LogPrintExit2 info $0 ("Updating A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false;
/ip/dns/static/set address=($LeaseVal->"active-address") name=$FullA $DnsRecord;
} }
} on-error={
$LogPrint debug $ScriptName ("A lease just vanished, ignoring.");
}
:local CName [ /ip/dns/static/find where comment=$Comment type=CNAME ]; :if ([ :len ($LeaseVal->"active-address") ] > 0) do={
:if ([ :len $CName ] > 0) do={ :local Comment ($CommentPrefix . ", macaddress=" . $LeaseVal->"active-mac-address" . ", server=" . $LeaseVal->"server");
:local CNameVal [ /ip/dns/static/get $CName ]; :local MacDash [ $CleanName ($LeaseVal->"active-mac-address") ];
:if ($CNameVal->"name" != $FullCN || $CNameVal->"cname" != $FullA) do={ :local HostName [ $CleanName [ $EitherOr ([ $ParseKeyValueStore ($LeaseVal->"comment") ]->"hostname") ($LeaseVal->"host-name") ] ];
$LogPrintExit2 info $0 ("Deleting CNAME record with wrong data for " . $MacInServer . ".") false; :local Network [ /ip/dhcp-server/network/find where ($LeaseVal->"active-address") in address ];
/ip/dns/static/remove $CName; :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 $HostName ] > 0 && [ :len [ /ip/dns/static/find where name=$FullCN type=CNAME ] ] = 0) do={
$LogPrintExit2 info $0 ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ").") false;
/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={ } else={
$LogPrintExit2 info $0 ("Adding A record for " . $MacInServer . " (" . $FullA . " -> " . $LeaseVal->"active-address" . ").") false; $LogPrint debug $ScriptName ("No address available... Ignoring.");
/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={
$LogPrintExit2 info $0 ("Adding CNAME record for " . $MacInServer . " (" . $FullCN . " -> " . $FullA . ").") false;
/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 $0 ("The name '" . $FullA . "' appeared in more than one A record!") false;
}
} else={
$LogPrintExit2 debug $0 ("No address available... Ignoring.") false;
} }
} } on-error={ }

View file

@ -1,6 +1,13 @@
Find and remove access list duplicates Find and remove access list duplicates
====================================== ======================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -15,19 +22,14 @@ entries in wireless access list.
Requirements and installation Requirements and installation
----------------------------- -----------------------------
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`), legacy
package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) or local wireless interface
or local wireless interface (`/interface/wireless`) you need to install a (`/interface/wireless`) you need to install a different script.
different script.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate accesslist-duplicates.wifi; $ScriptInstallUpdate accesslist-duplicates.wifi;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate accesslist-duplicates.wifiwave2;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate accesslist-duplicates.capsman; $ScriptInstallUpdate accesslist-duplicates.capsman;

View file

@ -1,6 +1,13 @@
Upload backup to Mikrotik cloud Upload backup to Mikrotik cloud
=============================== ===============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -12,10 +19,10 @@ Description
This script uploads This script uploads
[binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup). [binary backup to Mikrotik cloud](https://wiki.mikrotik.com/wiki/Manual:IP/Cloud#Backup).
> ⚠️ **Warning**: The used command can hit errors that a script can not handle. > ⚠️ **Warning**: The used command can hit errors that a script can with
> This may result in script termination (where no notification is sent) or > workaround only. A notification *should* be sent anyway. But it can result
> malfunction of fetch command (where all up- and downloads break) for some > in malfunction of fetch command (where all up- and downloads break) for
> time. Failed notifications are queued then. > some time. Failed notifications are queued then.
### Sample notification ### Sample notification

View file

@ -1,6 +1,13 @@
Send backup via e-mail Send backup via e-mail
====================== ======================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Save configuration to fallback partition Save configuration to fallback partition
======================================== ========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Upload backup to server Upload backup to server
======================= =======================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Download packages for CAP upgrade from CAPsMAN Download packages for CAP upgrade from CAPsMAN
============================================= =============================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -23,31 +30,21 @@ as that is where packages are downloaded to and where the system expects
them. them.
Then just install the script on CAPsMAN device. Then just install the script on CAPsMAN device.
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`) or legacy
package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) you need to install a different script.
you need to install a different script.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate capsman-download-packages.wifi; $ScriptInstallUpdate capsman-download-packages.wifi;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate capsman-download-packages.wifiwave2;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate capsman-download-packages.capsman; $ScriptInstallUpdate capsman-download-packages.capsman;
Optionally add a scheduler to run after startup. For `wifi` (RouterOS 7.13 Optionally add a scheduler to run after startup. For `wifi`:
and later):
/system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifi;" start-time=startup; /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifi;" start-time=startup;
For `wifiwave2` (up to RouterOS 7.12):
/system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.wifiwave2;" start-time=startup;
For legacy CAPsMAN: For legacy CAPsMAN:
/system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup; /system/scheduler/add name=capsman-download-packages on-event="/system/script/run capsman-download-packages.capsman;" start-time=startup;
@ -58,7 +55,6 @@ unconditionally.
If no packages are found the script downloads a default set of packages: 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* * `wifi`: `routeros` and `wifi-qcom` for *arm* and *arm64*, `wifi-qcom-ac` for *arm*
* `wifiwave2`: `routeros` and `wifiwave2` for *arm* and *arm64*
* legacy CAPsMAN: `routeros` and `wireless` for *arm* and *mipsbe* * legacy CAPsMAN: `routeros` and `wireless` for *arm* and *mipsbe*
> **Info**: If you have packages in the directory and things go wrong for > **Info**: If you have packages in the directory and things go wrong for

View file

@ -1,6 +1,13 @@
Run rolling CAP upgrades from CAPsMAN Run rolling CAP upgrades from CAPsMAN
===================================== =====================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -21,18 +28,13 @@ Requirements and installation
----------------------------- -----------------------------
Just install the script on CAPsMAN device. Just install the script on CAPsMAN device.
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`) or legacy
package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) you need to install a different script.
you need to install a different script.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate capsman-rolling-upgrade.wifi; $ScriptInstallUpdate capsman-rolling-upgrade.wifi;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate capsman-rolling-upgrade.wifiwave2;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate capsman-rolling-upgrade.capsman; $ScriptInstallUpdate capsman-rolling-upgrade.capsman;

View file

@ -1,6 +1,13 @@
Renew locally issued certificates Renew locally issued certificates
================================= =================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Renew certificates and notify on expiration Renew certificates and notify on expiration
=========================================== ===========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Notify about health state Notify about health state
========================= =========================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Notify on LTE firmware upgrade Notify on LTE firmware upgrade
============================== ==============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Notify on RouterOS update Notify on RouterOS update
========================= =========================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Collect MAC addresses in wireless access list Collect MAC addresses in wireless access list
============================================= =============================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -22,19 +29,14 @@ and modify it to your needs.
Requirements and installation Requirements and installation
----------------------------- -----------------------------
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`), legacy
package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) or local wireless interface
or local wireless interface (`/interface/wireless`) you need to install a (`/interface/wireless`) you need to install a different script.
different script.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate collect-wireless-mac.wifi; $ScriptInstallUpdate collect-wireless-mac.wifi;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate collect-wireless-mac.wifiwave2;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate collect-wireless-mac.capsman; $ScriptInstallUpdate collect-wireless-mac.capsman;

View file

@ -1,6 +1,13 @@
Use wireless network with daily psk Use wireless network with daily psk
=================================== ===================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -21,23 +28,17 @@ Requirements and installation
Just install this script. Just install this script.
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`), legacy
package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) or local wireless interface
or local wireless interface (`/interface/wireless`) you need to install a (`/interface/wireless`) you need to install a different script and add
different script and add schedulers to run the script: schedulers to run the script:
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate daily-psk.wifi; $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 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; /system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.wifi;" start-time=startup;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate daily-psk.wifiwave2;
/system/scheduler/add interval=1d name=daily-psk on-event="/system/script/run daily-psk.wifiwave2;" start-time=03:00:00;
/system/scheduler/add name=daily-psk@startup on-event="/system/script/run daily-psk.wifiwave2;" start-time=startup;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate daily-psk.capsman; $ScriptInstallUpdate daily-psk.capsman;
@ -64,14 +65,10 @@ The configuration goes to `global-config-overlay`, these are the parameters:
> [`global-config`](../global-config.rsc) (the one without `-overlay`) to > [`global-config`](../global-config.rsc) (the one without `-overlay`) to
> your local `global-config-overlay` and modify it to your specific needs. > your local `global-config-overlay` and modify it to your specific needs.
Then add an access list entry. For `wifi` (RouterOS 7.13 and later): Then add an access list entry. For `wifi`:
/interface/wifi/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily"; /interface/wifi/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily";
For `wifiwave2` (up to RouterOS 7.12):
/interface/wifiwave2/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" passphrase="ToBeChangedDaily";
For legacy CAPsMAN: For legacy CAPsMAN:
/caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily"; /caps-man/access-list/add comment="Daily PSK" ssid-regexp="-guest\$" private-passphrase="ToBeChangedDaily";

View file

@ -1,6 +1,13 @@
Comment DHCP leases with info from access list Comment DHCP leases with info from access list
============================================== ==============================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -15,19 +22,14 @@ from wireless access list.
Requirements and installation Requirements and installation
----------------------------- -----------------------------
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`), legacy
package (`/interface/wifiwave2`), legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) or local wireless interface
or local wireless interface (`/interface/wireless`) you need to install a (`/interface/wireless`) you need to install a different script.
different script.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate dhcp-lease-comment.wifi; $ScriptInstallUpdate dhcp-lease-comment.wifi;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate dhcp-lease-comment.wifiwave2;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate dhcp-lease-comment.capsman; $ScriptInstallUpdate dhcp-lease-comment.capsman;

View file

@ -1,6 +1,13 @@
Create DNS records for DHCP leases Create DNS records for DHCP leases
================================== ==================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Automatically upgrade firmware and reboot Automatically upgrade firmware and reboot
========================================= =========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Download, import and update firewall address-lists 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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -56,8 +63,12 @@ available in my repository and downloaded automatically. Import it manually
(menu `/certificate/`) if missing. (menu `/certificate/`) if missing.
Create firewall rules to process the packets that are related to addresses Create firewall rules to process the packets that are related to addresses
from address-lists. This rejects the packets from and to ip addresses listed from address-lists.
in address-list `block`.
### 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=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 src-address-list=block action=reject reject-with=icmp-admin-prohibited;
@ -85,6 +96,33 @@ Alternatively handle the packets in firewall's raw section if you prefer:
> ⚠️ **Warning**: Just again... The order of firewall rules is important. Make > ⚠️ **Warning**: Just again... The order of firewall rules is important. Make
> sure they actually take effect as expected! > 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 main README](../README.md)
[⬆️ Go back to top](#top) [⬆️ Go back to top](#top)

View file

@ -1,6 +1,13 @@
Wait for global functions and modules Wait for global functions and modules
===================================== =====================================
[![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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Send GPS position to server Send GPS position to server
=========================== ===========================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Use WPA network with hotspot credentials Use WPA network with hotspot credentials
======================================== ========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -20,21 +27,15 @@ You need a properly configured hotspot on one (open) SSID and a WPA enabled
SSID with suffix "`-wpa`". SSID with suffix "`-wpa`".
Then install the script. Then install the script.
Depending on whether you use `wifi` package (`/interface/wifi`), `wifiwave2` Depending on whether you use `wifi` package (`/interface/wifi`)or legacy
package (`/interface/wifiwave2`) or legacy wifi with CAPsMAN (`/caps-man`) wifi with CAPsMAN (`/caps-man`) you need to install a different script and
you need to install a different script and set it as `on-login` script in set it as `on-login` script in hotspot.
hotspot.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate hotspot-to-wpa.wifi; $ScriptInstallUpdate hotspot-to-wpa.wifi;
/ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifi" [ find ]; /ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifi" [ find ];
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate hotspot-to-wpa.wifiwave2;
/ip/hotspot/user/profile/set on-login="hotspot-to-wpa.wifiwave2" [ find ];
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate hotspot-to-wpa.capsman; $ScriptInstallUpdate hotspot-to-wpa.capsman;
@ -46,16 +47,11 @@ 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. and add a scheduler.
For `wifi` (RouterOS 7.13 and later): For `wifi`:
$ScriptInstallUpdate hotspot-to-wpa-cleanup.wifi,lease-script; $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; /system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.wifi;" start-time=startup;
For `wifiwave2` (up to RouterOS 7.12):
$ScriptInstallUpdate hotspot-to-wpa-cleanup.wifiwave2,lease-script;
/system/scheduler/add interval=1d name=hotspot-to-wpa-cleanup on-event="/system/script/run hotspot-to-wpa-cleanup.wifiwave2;" start-time=startup;
For legacy CAPsMAN: For legacy CAPsMAN:
$ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,lease-script; $ScriptInstallUpdate hotspot-to-wpa-cleanup.capsman,lease-script;
@ -97,15 +93,11 @@ Additionally templates can be created to give more options for access list:
* `vlan-id`: connect device to specific VLAN * `vlan-id`: connect device to specific VLAN
* `vlan-mode`: set the VLAN mode for device * `vlan-mode`: set the VLAN mode for device
For a hotspot called `example` the template could look like this. For For a hotspot called `example` the template could look like this.
`wifi` (RouterOS 7.13 and later): For `wifi`:
/interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10; /interface/wifi/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10;
For `wifiwave2` (up to RouterOS 7.12):
/interface/wifiwave2/access-list/add comment="hotspot-to-wpa template example" disabled=yes passphrase="ignore" ssid-regexp="^example\$" vlan-id=10;
For legacy CAPsMAN: 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; /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;

View file

@ -1,6 +1,13 @@
Manage IP addresses with bridge status Manage IP addresses with bridge status
====================================== ======================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
Description Description

View file

@ -1,6 +1,13 @@
Create DNS records for IPSec peers Create DNS records for IPSec peers
================================== ==================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Update configuration on IPv6 prefix change Update configuration on IPv6 prefix change
========================================== ==========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Run other scripts on DHCP lease Run other scripts on DHCP lease
=============================== ===============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Manage LEDs dark mode Manage LEDs dark mode
===================== =====================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
Description Description

View file

@ -1,6 +1,13 @@
Forward log messages via notification Forward log messages via notification
===================================== =====================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Manage ports in bridge Manage ports in bridge
====================== ======================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Manage VLANs on bridge ports Manage VLANs on bridge ports
============================ ============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Inspect variables Inspect variables
================= =================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
IP address calculation IP address calculation
====================== ======================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Send notifications via e-mail Send notifications via e-mail
============================= =============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Send notifications via Matrix Send notifications via Matrix
============================= =============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Send notifications via Ntfy 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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Send notifications via Telegram Send notifications via Telegram
=============================== ===============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Download script and run it once Download script and run it once
=============================== ===============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Import ssh keys for public key authentication 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) [⬅️ Go back to main README](../../README.md)
> **Info**: This module can not be used on its own but requires the base > **Info**: This module can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Mode button with multiple presses Mode button with multiple presses
================================= =================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Manage DNS and DoH servers from netwatch Manage DNS and DoH servers from netwatch
======================================== ========================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Notify on host up and down Notify on host up and down
========================== ==========================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -83,9 +90,9 @@ with a resolvable name:
/tool/netwatch/add comment="notify, name=example.com, resolve=example.com"; /tool/netwatch/add comment="notify, name=example.com, resolve=example.com";
But be warned: Dynamic updates will probably cause issues if the name has This supports multiple A or AAAA records for a name just fine, even a CNAME
more than one record in dns - a high rate of configuration changes (and flash to those. An update happens only if no more record with the configured host
writes) at least. address is found.
### No notification on host down ### No notification on host down

View file

@ -1,6 +1,13 @@
Visualize OSPF state via LEDs Visualize OSPF state via LEDs
============================= =============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Manage system update Manage system update
==================== ====================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Run scripts on ppp connection Run scripts on ppp connection
============================= =============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Act on received SMS Act on received SMS
=================== ===================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Forward received SMS Forward received SMS
==================== ====================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Play Super Mario theme Play Super Mario theme
====================== ======================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
Description Description

View file

@ -1,6 +1,13 @@
Chat with your router and send commands via Telegram bot 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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base
@ -100,6 +107,14 @@ scripting capabilities. Try to print what you want to act on...
/ip/address/remove [ find where interface=eth ]; /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 ### Mind command runtime
The command is run in background while the script waits for it - about The command is run in background while the script waits for it - about

View file

@ -1,6 +1,13 @@
Install LTE firmware upgrade Install LTE firmware upgrade
============================ ============================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
Description Description

View file

@ -1,6 +1,13 @@
Update GRE configuration with dynamic addresses Update GRE configuration with dynamic addresses
=============================================== ===============================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -1,6 +1,13 @@
Update tunnelbroker configuration Update tunnelbroker configuration
================================= =================================
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.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) [⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base > **Info**: This script can not be used on its own but requires the base

View file

@ -8,40 +8,47 @@
# install firmware upgrade, and reboot # install firmware upgrade, and reboot
# https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/firmware-upgrade-reboot.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global LogPrintExit2; :do {
:global ScriptLock; :local ScriptName [ :jobname ];
:global VersionToNum;
$ScriptLock $0; :global LogPrint;
:global ScriptLock;
:global VersionToNum;
:local RouterBoard [ /system/routerboard/get ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={ :error false;
$LogPrintExit2 info $0 ("Current and upgrade firmware match with version " . \ }
$RouterBoard->"current-firmware" . ".") true;
}
:if ([ $VersionToNum ($RouterBoard->"current-firmware") ] > [ $VersionToNum ($RouterBoard->"upgrade-firmware") ]) do={
$LogPrintExit2 info $0 ("Different firmware version is available, but it is a downgrade. Ignoring.") true;
}
:if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={ :local RouterBoard [ /system/routerboard/get ];
$LogPrintExit2 info $0 ("Firmware version " . $RouterBoard->"upgrade-firmware" . \ :if ($RouterBoard->"current-firmware" = $RouterBoard->"upgrade-firmware") do={
" is available, upgrading.") false; $LogPrint info $ScriptName ("Current and upgrade firmware match with version " . \
/system/routerboard/upgrade; $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;
}
:while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \ :if ([ /system/routerboard/settings/get auto-upgrade ] = false) do={
message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={ $LogPrint info $ScriptName ("Firmware version " . $RouterBoard->"upgrade-firmware" . \
:delay 1s; " is available, upgrading.");
} /system/routerboard/upgrade;
}
:local Uptime [ /system/resource/get uptime ]; :while ([ :len [ /log/find where topics=({"system";"info";"critical"}) \
:if ($Uptime < 1m) do={ message="Firmware upgraded successfully, please reboot for changes to take effect!" ] ] = 0) do={
:delay $Uptime; :delay 1s;
} }
$LogPrintExit2 info $0 ("Firmware upgrade successful, rebooting.") false; :local Uptime [ /system/resource/get uptime ];
/system/reboot; :if ($Uptime < 1m) do={
:delay $Uptime;
}
$LogPrint info $ScriptName ("Firmware upgrade successful, rebooting.");
/system/reboot;
} on-error={ }

View file

@ -8,115 +8,152 @@
# download, import and update firewall address-lists # download, import and update firewall address-lists
# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global FetchUserAgent; :do {
:global FwAddrLists; :local ScriptName [ :jobname ];
:global FwAddrListTimeOut;
:global CertificateAvailable; :global FetchUserAgent;
:global EitherOr; :global FwAddrLists;
:global LogPrintExit2; :global FwAddrListTimeOut;
:global LogPrintOnce;
:global ScriptLock;
:global WaitFullyConnected;
:local FindDelim do={ :global CertificateAvailable;
:local ValidChars "0123456789./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"; :global EitherOr;
:for I from=0 to=[ :len $1 ] do={ :global LogPrint;
:if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ :global LogPrintOnce;
:return $I; :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;
}
} }
} }
}
$ScriptLock $0; :if ([ $ScriptLock $ScriptName ] = false) do={
$WaitFullyConnected; :error false;
}
$WaitFullyConnected;
:local ListComment ("managed by " . $0); :local ListComment ("managed by " . $ScriptName);
:foreach FwListName,FwList in=$FwAddrLists do={ :foreach FwListName,FwList in=$FwAddrLists do={
:local Addresses ({}); :local CntAdd 0;
:local CntAdd 0; :local CntRenew 0;
:local CntRenew 0; :local CntRemove 0;
:local CntRemove 0; :local IPv4Addresses ({});
:local Failure false; :local IPv6Addresses ({});
:local Failure false;
:foreach List in=$FwList do={ :foreach List in=$FwList do={
:local CheckCertificate "no"; :local CheckCertificate "no";
:local Data false; :local Data false;
:local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ]; :local TimeOut [ $EitherOr [ :totime ($List->"timeout") ] $FwAddrListTimeOut ];
:if ([ :len ($List->"cert") ] > 0) do={ :if ([ :len ($List->"cert") ] > 0) do={
:set CheckCertificate "yes-without-crl"; :set CheckCertificate "yes-without-crl";
:if ([ $CertificateAvailable ($List->"cert") ] = false) do={ :if ([ $CertificateAvailable ($List->"cert") ] = false) do={
$LogPrintExit2 warning $0 ("Downloading required certificate failed, trying anyway.") false; $LogPrint warning $ScriptName ("Downloading required certificate failed, trying anyway.");
}
}
:for I from=1 to=4 do={
:if ($Data = false) do={
:do {
:set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \
http-header-field=({ $FetchUserAgent }) ($List->"url") as-value ]->"data");
} on-error={
:if ($I < 4) 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 ] ];
} }
} }
:for I from=1 to=4 do={ :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={
:if ($Data = false) do={ :local Address [ /ip/firewall/address-list/get $Entry address ];
:do { :if ([ :typeof ($IPv4Addresses->$Address) ] = "time") do={
:set Data ([ /tool/fetch check-certificate=$CheckCertificate output=user \ $LogPrint debug $ScriptName ("Renewing IPv4 address for " . ($IPv4Addresses->$Address) . ": " . $Address);
http-header-field=({ $FetchUserAgent }) ($List->"url") as-value ]->"data"); /ip/firewall/address-list/set $Entry timeout=($IPv4Addresses->$Address);
} on-error={ :set ($IPv4Addresses->$Address);
:if ($I < 4) do={ :set CntRenew ($CntRenew + 1);
$LogPrintExit2 debug $0 ("Failed downloading, " . $I . ". try: " . $List->"url") false; } else={
:delay (($I * $I) . "s"); :if ($Failure = false) do={
} $LogPrint debug $ScriptName ("Removing IPv4 address: " . $Address);
/ip/firewall/address-list/remove $Entry;
:set CntRemove ($CntRemove + 1);
} }
} }
} }
:if ($Data = false) do={ :foreach Entry in=[ /ipv6/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={
:set Data ""; :local Address [ /ipv6/firewall/address-list/get $Entry address ];
:set Failure true; :if ([ :typeof ($IPv6Addresses->$Address) ] = "time") do={
$LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; $LogPrint debug $ScriptName ("Renewing IPv6 address for " . ($IPv6Addresses->$Address) . ": " . $Address);
} /ipv6/firewall/address-list/set $Entry timeout=($IPv6Addresses->$Address);
:set ($IPv6Addresses->$Address);
:if ([ :len $Data ] > 63000) do={ :set CntRenew ($CntRenew + 1);
$LogPrintOnce warning $0 ("The list is huge and may be truncated: " . $List->"url") false; } else={
} :if ($Failure = false) do={
$LogPrint debug $ScriptName ("Removing: " . $Address);
:while ([ :len $Data ] != 0) do={ /ipv6/firewall/address-list/remove $Entry;
:local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; :set CntRemove ($CntRemove + 1);
: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 ($Addresses->$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 ($Addresses->$Address) ] = "time") do={
$LogPrintExit2 debug $0 ("Renewing for " . ($Addresses->$Address) . ": " . $Address) false;
/ip/firewall/address-list/set $Entry timeout=($Addresses->$Address);
:set ($Addresses->$Address);
:set CntRenew ($CntRenew + 1);
} else={
:if ($Failure = false) do={
$LogPrintExit2 debug $0 ("Removing: " . $Address) false;
/ip/firewall/address-list/remove $Entry;
:set CntRemove ($CntRemove + 1);
} }
} }
}
:foreach Address,Ignore in=$Addresses do={ :foreach Address,Timeout in=$IPv4Addresses do={
$LogPrintExit2 debug $0 ("Adding for " . ($Addresses->$Address) . ": " . $Address) false; $LogPrint debug $ScriptName ("Adding IPv4 address for " . $Timeout . ": " . $Address);
:do { :do {
/ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=($Addresses->$Address); /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$Timeout;
:set ($Addresses->$Address); :set ($IPv4Addresses->$Address);
:set CntAdd ($CntAdd + 1); :set CntAdd ($CntAdd + 1);
} on-error={ } on-error={
$LogPrintExit2 warning $0 ("Failed to add address " . $Address . " to list '" . $FwListName . "'.") false; $LogPrint warning $ScriptName ("Failed to add IPv4 address " . $Address . " to list '" . $FwListName . "'.");
}
} }
}
$LogPrintExit2 info $0 ("list: " . $FwListName . " -- added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; :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={ }

View file

@ -243,10 +243,14 @@
"cert2-cn"="4n0th3r-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! # Warning: Do *NOT* copy this code to overlay!
:do { :foreach Script in=([ /system/script/find where name="global-config-overlay" ], \
/system/script/run global-config-overlay; [ /system/script/find where name~"^global-config-overlay.d/" ]) do={
} on-error={ :do {
:log error ("Loading configuration from overlay failed!"); /system/script/run $Script;
} on-error={
:log error ("Loading configuration from overlay or snippet " . \
[ /system/script/get $Script name ] . " failed!");
}
} }

View file

@ -9,14 +9,19 @@
# global functions # global functions
# https://git.eworm.de/cgit/routeros-scripts/about/ # https://git.eworm.de/cgit/routeros-scripts/about/
:local 0 [ :jobname ]; :local ScriptName [ :jobname ];
# expected configuration version # expected configuration version
:global ExpectedConfigVersion 118; :global ExpectedConfigVersion 123;
# global variables not to be changed by user # global variables not to be changed by user
:global GlobalFunctionsReady false; :global GlobalFunctionsReady false;
:global FetchUserAgent ("User-Agent: Mikrotik/" . [ /system/resource/get version ] . " Fetch"); :global FetchUserAgent;
{
:local Resource [ /system/resource/get ];
:set FetchUserAgent ("User-Agent: Mikrotik/" . $Resource->"version" . \
" " . $Resource->"architecture-name" . " Fetch");
}
:global Identity [ /system/identity/get name ]; :global Identity [ /system/identity/get name ];
# global functions # global functions
@ -48,6 +53,7 @@
:global IsFullyConnected; :global IsFullyConnected;
:global IsMacLocallyAdministered; :global IsMacLocallyAdministered;
:global IsTimeSync; :global IsTimeSync;
:global LogPrint;
:global LogPrintExit2; :global LogPrintExit2;
:global LogPrintOnce; :global LogPrintOnce;
:global MAX; :global MAX;
@ -96,18 +102,18 @@
:local CommonName [ :tostr $1 ]; :local CommonName [ :tostr $1 ];
:global CertificateDownload; :global CertificateDownload;
:global LogPrintExit2; :global LogPrint;
:global ParseKeyValueStore; :global ParseKeyValueStore;
:if ([ /system/resource/get free-hdd-space ] < 8388608 && \ :if ([ /system/resource/get free-hdd-space ] < 8388608 && \
[ /certificate/settings/get crl-download ] = true && \ [ /certificate/settings/get crl-download ] = true && \
[ /certificate/settings/get crl-store ] = "system") do={ [ /certificate/settings/get crl-store ] = "system") do={
$LogPrintExit2 warning $0 ("This system has low free flash space but " . \ $LogPrint warning $0 ("This system has low free flash space but " . \
"is configured to download certificate CRLs to system!") false; "is configured to download certificate CRLs to system!");
} }
:if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ :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={ :if ([ $CertificateDownload $CommonName ] = false) do={
:return false; :return false;
} }
@ -116,8 +122,8 @@
:local CertVal [ /certificate/get [ find where common-name=$CommonName ] ]; :local CertVal [ /certificate/get [ find where common-name=$CommonName ] ];
:while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={ :while (($CertVal->"akid") != "" && ($CertVal->"akid") != ($CertVal->"skid")) do={
:if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={ :if ([ :len [ /certificate/find where skid=($CertVal->"akid") ] ] = 0) do={
$LogPrintExit2 info $0 ("Certificate chain for \"" . $CommonName . \ $LogPrint info $0 ("Certificate chain for \"" . $CommonName . \
"\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".") false; "\" is incomplete, missing \"" . ([ $ParseKeyValueStore ($CertVal->"issuer") ]->"CN") . "\".");
:if ([ $CertificateDownload $CommonName ] = false) do={ :if ([ $CertificateDownload $CommonName ] = false) do={
:return false; :return false;
} }
@ -136,12 +142,12 @@
:global ScriptUpdatesUrlSuffix; :global ScriptUpdatesUrlSuffix;
:global CertificateNameByCN; :global CertificateNameByCN;
:global LogPrintExit2; :global LogPrint;
:global UrlEncode; :global UrlEncode;
:global WaitForFile; :global WaitForFile;
$LogPrintExit2 info $0 ("Downloading and importing certificate with " . \ $LogPrint info $0 ("Downloading and importing certificate with " . \
"CommonName \"" . $CommonName . "\".") false; "CommonName \"" . $CommonName . "\".");
:do { :do {
:local LocalFileName ($CommonName . ".pem"); :local LocalFileName ($CommonName . ".pem");
:local UrlFileName ([ $UrlEncode $CommonName ] . ".pem"); :local UrlFileName ([ $UrlEncode $CommonName ] . ".pem");
@ -157,8 +163,7 @@
$CertificateNameByCN [ /certificate/get $Cert common-name ]; $CertificateNameByCN [ /certificate/get $Cert common-name ];
} }
} on-error={ } on-error={
$LogPrintExit2 warning $0 ("Failed importing certificate with " . \ $LogPrint warning $0 ("Failed importing certificate with CommonName \"" . $CommonName . "\"!");
"CommonName \"" . $CommonName . "\"!") false;
:return false; :return false;
} }
:return true; :return true;
@ -303,7 +308,7 @@
:global CertificateAvailable; :global CertificateAvailable;
:global CleanFilePath; :global CleanFilePath;
:global LogPrintExit2; :global LogPrint;
:global MkDir; :global MkDir;
:global WaitForFile; :global WaitForFile;
@ -318,22 +323,23 @@
:local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ]; :local PkgDest [ $CleanFilePath ($PkgDir . "/" . $PkgFile) ];
:if ([ $MkDir $PkgDir ] = false) do={ :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; :return false;
} }
:if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ :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; :return true;
} }
:if ([ $CertificateAvailable "R3" ] = false) do={ :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); :local Url ("https://upgrade.mikrotik.com/routeros/" . $PkgVer . "/" . $PkgFile);
$LogPrintExit2 info $0 ("Downloading package file '" . $PkgName . "'...") false; $LogPrint info $0 ("Downloading package file '" . $PkgName . "'...");
$LogPrintExit2 debug $0 ("... from url: " . $Url) false; $LogPrint debug $0 ("... from url: " . $Url);
:local Retry 3; :local Retry 3;
:while ($Retry > 0) do={ :while ($Retry > 0) do={
:do { :do {
@ -344,14 +350,14 @@
:return true; :return true;
} }
} on-error={ } on-error={
$LogPrintExit2 debug $0 ("Downloading package file failed.") false; $LogPrint debug $0 ("Downloading package file failed.");
} }
/file/remove [ find where name=$PkgDest ]; /file/remove [ find where name=$PkgDest ];
:set Retry ($Retry - 1); :set Retry ($Retry - 1);
} }
$LogPrintExit2 warning $0 ("Downloading package file '" . $PkgName . "' failed.") false; $LogPrint warning $0 ("Downloading package file '" . $PkgName . "' failed.");
:return false; :return false;
} }
@ -437,7 +443,7 @@
:global CertificateAvailable; :global CertificateAvailable;
:global IsMacLocallyAdministered; :global IsMacLocallyAdministered;
:global LogPrintExit2; :global LogPrint;
:if ([ $IsMacLocallyAdministered $Mac ] = true) do={ :if ([ $IsMacLocallyAdministered $Mac ] = true) do={
:return "locally administered"; :return "locally administered";
@ -445,7 +451,8 @@
:do { :do {
:if ([ $CertificateAvailable "GTS CA 1P5" ] = false) do={ :if ([ $CertificateAvailable "GTS CA 1P5" ] = false) do={
$LogPrintExit2 warning $0 ("Downloading required certificate failed.") true; $LogPrint warning $0 ("Downloading required certificate failed.");
:error false;
} }
:local Vendor ([ /tool/fetch check-certificate=yes-without-crl \ :local Vendor ([ /tool/fetch check-certificate=yes-without-crl \
("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data"); ("https://api.macvendors.com/" . [ :pick $Mac 0 8 ]) output=user as-value ]->"data");
@ -454,9 +461,9 @@
:do { :do {
/tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \ /tool/fetch check-certificate=yes-without-crl ("https://api.macvendors.com/") \
output=none as-value; output=none as-value;
$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={ } on-error={
$LogPrintExit2 warning $0 ("Failed getting mac vendor.") false; $LogPrint warning $0 ("Failed getting mac vendor.");
} }
:return "unknown vendor"; :return "unknown vendor";
} }
@ -603,7 +610,7 @@
:global IsTimeSyncCached; :global IsTimeSyncCached;
:global IsTimeSyncResetNtp; :global IsTimeSyncResetNtp;
:global LogPrintExit2; :global LogPrint;
:if ($IsTimeSyncCached = true) do={ :if ($IsTimeSyncCached = true) do={
:return true; :return true;
@ -632,7 +639,7 @@
:if ([ /system/license/get ]->"level" = "free" || \ :if ([ /system/license/get ]->"level" = "free" || \
[ /system/resource/get ]->"board-name" = "x86") do={ [ /system/resource/get ]->"board-name" = "x86") do={
$LogPrintExit2 debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86.") false; $LogPrint debug $0 ("No ntp client configured, relying on RTC for CHR free license and x86.");
:return true; :return true;
} }
@ -644,16 +651,15 @@
:return false; :return false;
} }
$LogPrintExit2 debug $0 ("No time source configured! Returning gracefully...") false; $LogPrint debug $0 ("No time source configured! Returning gracefully...");
:return true; :return true;
} }
# log and print with same text, optionally exit # log and print with same text
:set LogPrintExit2 do={ :set LogPrint do={
:local Severity [ :tostr $1 ]; :local Severity [ :tostr $1 ];
:local Name [ :tostr $2 ]; :local Name [ :tostr $2 ];
:local Message [ :tostr $3 ]; :local Message [ :tostr $3 ];
:local Exit [ :tostr $4 ];
:global PrintDebug; :global PrintDebug;
:global PrintDebugOverride; :global PrintDebugOverride;
@ -686,6 +692,19 @@
:if ($Severity != "debug" || $Debug = true) do={ :if ($Severity != "debug" || $Debug = true) do={
: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;
$LogPrint $1 $2 $3;
:if ($Exit = "true") do={ :if ($Exit = "true") do={
:error ("Hard error to exit."); :error ("Hard error to exit.");
@ -697,9 +716,8 @@
:local Severity [ :tostr $1 ]; :local Severity [ :tostr $1 ];
:local Name [ :tostr $2 ]; :local Name [ :tostr $2 ];
:local Message [ :tostr $3 ]; :local Message [ :tostr $3 ];
:local Exit [ :tostr $4 ];
:global LogPrintExit2; :global LogPrint;
:global LogPrintOnceMessages; :global LogPrintOnceMessages;
@ -712,7 +730,7 @@
} }
:set ($LogPrintOnceMessages->$Message) 1; :set ($LogPrintOnceMessages->$Message) 1;
$LogPrintExit2 $Severity $Name $Message $Exit; $LogPrint $Severity $Name $Message;
} }
# get max value # get max value
@ -732,24 +750,24 @@
:local Path [ :tostr $1 ]; :local Path [ :tostr $1 ];
:global CleanFilePath; :global CleanFilePath;
:global LogPrintExit2; :global LogPrint;
:global WaitForFile; :global WaitForFile;
:local MkTmpfs do={ :local MkTmpfs do={
:global LogPrintExit2; :global LogPrint;
:global WaitForFile; :global WaitForFile;
:if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={ :if ([ :len [ /disk/find where slot=tmpfs type=tmpfs ] ] = 1) do={
:return true; :return true;
} }
$LogPrintExit2 info $0 ("Creating disk of type tmpfs.") false; $LogPrint info $0 ("Creating disk of type tmpfs.");
/file/remove [ find where name="tmpfs" type="directory" ]; /file/remove [ find where name="tmpfs" type="directory" ];
:do { :do {
/disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3); /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/get total-memory ] / 3);
$WaitForFile "tmpfs"; $WaitForFile "tmpfs";
} on-error={ } on-error={
$LogPrintExit2 warning $0 ("Creating disk of type tmpfs failed!") false; $LogPrint warning $0 ("Creating disk of type tmpfs failed!");
:return false; :return false;
} }
:return true; :return true;
@ -777,7 +795,7 @@
$WaitForFile $File; $WaitForFile $File;
/file/remove $File; /file/remove $File;
} on-error={ } on-error={
$LogPrintExit2 warning $0 ("Making directory '" . $Path . "' failed!") false; $LogPrint warning $0 ("Making directory '" . $Path . "' failed!");
:return false; :return false;
} }
@ -908,18 +926,18 @@
:local Warn [ :tostr $3 ]; :local Warn [ :tostr $3 ];
:global IfThenElse; :global IfThenElse;
:global LogPrintExit2; :global LogPrint;
:global VersionToNum; :global VersionToNum;
:if (!($Required ~ "^\\d+\\.\\d+((alpha|beta|rc|\\.)\\d+|)\$")) do={ :if (!($Required ~ "^\\d+\\.\\d+((alpha|beta|rc|\\.)\\d+|)\$")) do={
$LogPrintExit2 error $0 ("No valid RouterOS version: " . $Required) false; $LogPrint error $0 ("No valid RouterOS version: " . $Required);
:return false; :return false;
} }
:if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={ :if ([ $VersionToNum $Required ] > [ $VersionToNum [ /system/package/update/get installed-version ] ]) do={
:if ($Warn = "true") do={ :if ($Warn = "true") do={
$LogPrintExit2 warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \ $LogPrint warning $0 ("This " . [ $IfThenElse ([ :pick $Caller 0 ] = ("\$")) "function" "script" ] . \
" '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!") false; " '" . $Caller . "' (at least specific functionality) requires RouterOS " . $Required . ". Please update!");
} }
:return false; :return false;
} }
@ -930,7 +948,7 @@
:set ScriptFromTerminal do={ :set ScriptFromTerminal do={
:local Script [ :tostr $1 ]; :local Script [ :tostr $1 ];
:global LogPrintExit2; :global LogPrint;
:foreach Job in=[ /system/script/job/find where script=$Script ] do={ :foreach Job in=[ /system/script/job/find where script=$Script ] do={
:set Job [ /system/script/job/get $Job ]; :set Job [ /system/script/job/get $Job ];
@ -938,11 +956,11 @@
:set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ]; :set Job [ /system/script/job/get [ find where .id=($Job->"parent") ] ];
} }
:if (($Job->"type") = "login") do={ :if (($Job->"type") = "login") do={
$LogPrintExit2 debug $0 ("Script " . $Script . " started from terminal.") false; $LogPrint debug $0 ("Script " . $Script . " started from terminal.");
:return true; :return true;
} }
} }
$LogPrintExit2 debug $0 ("Script " . $Script . " NOT started from terminal.") false; $LogPrint debug $0 ("Script " . $Script . " NOT started from terminal.");
:return false; :return false;
} }
@ -964,7 +982,7 @@
:global EitherOr; :global EitherOr;
:global Grep; :global Grep;
:global IfThenElse; :global IfThenElse;
:global LogPrintExit2; :global LogPrint;
:global LogPrintOnce; :global LogPrintOnce;
:global ParseKeyValueStore; :global ParseKeyValueStore;
:global RequiredRouterOS; :global RequiredRouterOS;
@ -973,12 +991,12 @@
:global ValidateSyntax; :global ValidateSyntax;
:if ([ $CertificateAvailable "E1" ] = false) do={ :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={ :foreach Script in=$Scripts do={
:if ([ :len [ /system/script/find where name=$Script ] ] = 0) 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; /system/script/add name=$Script owner=$Script source="#!rsc by RouterOS\n" comment=$NewComment;
} }
} }
@ -995,8 +1013,8 @@
:foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={ :foreach Scheduler in=[ /system/scheduler/find where on-event~("\\b" . $ScriptVal->"name" . "\\b") ] do={
:local SchedulerVal [ /system/scheduler/get $Scheduler ]; :local SchedulerVal [ /system/scheduler/get $Scheduler ];
:if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={ :if ($ScriptVal->"policy" != $SchedulerVal->"policy") do={
$LogPrintExit2 warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \ $LogPrint warning $0 ("Policies differ for script '" . $ScriptVal->"name" . \
"' and its scheduler '" . $SchedulerVal->"name" . "'!") false; "' and its scheduler '" . $SchedulerVal->"name" . "'!");
} }
} }
@ -1005,7 +1023,7 @@
:local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ]; :local BaseUrl [ $EitherOr ($ScriptInfo->"base-url") $ScriptUpdatesBaseUrl ];
:local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ]; :local UrlSuffix [ $EitherOr ($ScriptInfo->"url-suffix") $ScriptUpdatesUrlSuffix ];
:local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix); :local Url ($BaseUrl . $ScriptVal->"name" . ".rsc" . $UrlSuffix);
$LogPrintExit2 debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url) false; $LogPrint debug $0 ("Fetching script '" . $ScriptVal->"name" . "' from url: " . $Url);
:local Result [ /tool/fetch check-certificate=yes-without-crl \ :local Result [ /tool/fetch check-certificate=yes-without-crl \
http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; http-header-field=({ $FetchUserAgent }) $Url output=user as-value ];
:if ($Result->"status" = "finished") do={ :if ($Result->"status" = "finished") do={
@ -1013,11 +1031,11 @@
} }
} on-error={ } on-error={
:if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={ :if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={
$LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \ $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . \
"', removing dummy. Typo on installation?") false; "', removing dummy. Typo on installation?");
/system/script/remove $Script; /system/script/remove $Script;
} else={ } else={
$LogPrintExit2 warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!") false; $LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "'!");
} }
} }
} }
@ -1028,7 +1046,7 @@
:local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version"); :local Required ([ $ParseKeyValueStore [ $Grep $SourceNew ("\23 requires RouterOS, ") ] ]->"version");
:if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={ :if ([ $RequiredRouterOS $0 [ $EitherOr $Required "0.0" ] false ] = true) do={
:if ([ $ValidateSyntax $SourceNew ] = true) do={ :if ([ $ValidateSyntax $SourceNew ] = true) do={
$LogPrintExit2 info $0 ("Updating script: " . $ScriptVal->"name") false; $LogPrint info $0 ("Updating script: " . $ScriptVal->"name");
/system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script; /system/script/set owner=($ScriptVal->"name") source=$SourceNew $Script;
:if ($ScriptVal->"name" = "global-config") do={ :if ($ScriptVal->"name" = "global-config") do={
:set ReloadGlobalConfig true; :set ReloadGlobalConfig true;
@ -1037,48 +1055,48 @@
:set ReloadGlobalFunctions true; :set ReloadGlobalFunctions true;
} }
} else={ } else={
$LogPrintExit2 warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \ $LogPrint warning $0 ("Syntax validation for script '" . $ScriptVal->"name" . \
"' failed! Ignoring!") false; "' failed! Ignoring!");
} }
} else={ } else={
$LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \ $LogPrintOnce warning $0 ("The script '" . $ScriptVal->"name" . "' requires RouterOS " . \
$Required . ", which is not met by your installation. Ignoring!") false; $Required . ", which is not met by your installation. Ignoring!");
} }
} else={ } else={
$LogPrintExit2 warning $0 ("Looks like new script '" . $ScriptVal->"name" . \ $LogPrint warning $0 ("Looks like new script '" . $ScriptVal->"name" . \
"' is not valid (missing shebang). Ignoring!") false; "' is not valid (missing shebang). Ignoring!");
} }
} else={ } else={
$LogPrintExit2 debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.") false; $LogPrint debug $0 ("Script '" . $ScriptVal->"name" . "' did not change.");
} }
} else={ } else={
$LogPrintExit2 debug $0 ("No update for script '" . $ScriptVal->"name" . "'.") false; $LogPrint debug $0 ("No update for script '" . $ScriptVal->"name" . "'.");
} }
} }
:if ($ReloadGlobalFunctions = true) do={ :if ($ReloadGlobalFunctions = true) do={
$LogPrintExit2 info $0 ("Reloading global functions.") false; $LogPrint info $0 ("Reloading global functions.");
:do { :do {
/system/script/run global-functions; /system/script/run global-functions;
} on-error={ } on-error={
$LogPrintExit2 error $0 ("Reloading global functions failed!") false; $LogPrint error $0 ("Reloading global functions failed!");
} }
} }
:if ($ReloadGlobalConfig = true) do={ :if ($ReloadGlobalConfig = true) do={
$LogPrintExit2 info $0 ("Reloading global configuration.") false; $LogPrint info $0 ("Reloading global configuration.");
:do { :do {
/system/script/run global-config; /system/script/run global-config;
} on-error={ } on-error={
$LogPrintExit2 error $0 ("Reloading global configuration failed!" . \ $LogPrint error $0 ("Reloading global configuration failed!" . \
" Syntax error or missing overlay?") false; " Syntax error or missing overlay?");
} }
} }
:if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={ :if ($ExpectedConfigVersionBefore > $ExpectedConfigVersion) do={
$LogPrintExit2 warning $0 ("The configuration version decreased from " . \ $LogPrint warning $0 ("The configuration version decreased from " . \
$ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \ $ExpectedConfigVersionBefore . " to " . $ExpectedConfigVersion . \
". Installed an older version?") false; ". Installed an older version?");
} }
:if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={ :if ($ExpectedConfigVersionBefore < $ExpectedConfigVersion) do={
@ -1088,14 +1106,14 @@
:do { :do {
:local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix); :local Url ($ScriptUpdatesBaseUrl . "news-and-changes.rsc" . $ScriptUpdatesUrlSuffix);
$LogPrintExit2 debug $0 ("Fetching news, changes and migration: " . $Url) false; $LogPrint debug $0 ("Fetching news, changes and migration: " . $Url);
:local Result [ /tool/fetch check-certificate=yes-without-crl \ :local Result [ /tool/fetch check-certificate=yes-without-crl \
http-header-field=({ $FetchUserAgent }) $Url output=user as-value ]; http-header-field=({ $FetchUserAgent }) $Url output=user as-value ];
:if ($Result->"status" = "finished") do={ :if ($Result->"status" = "finished") do={
:set ChangeLogCode ($Result->"data"); :set ChangeLogCode ($Result->"data");
} }
} on-error={ } 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={ :if ([ :len $ChangeLogCode ] > 0) do={
@ -1103,10 +1121,10 @@
:do { :do {
[ :parse $ChangeLogCode ]; [ :parse $ChangeLogCode ];
} on-error={ } on-error={
$LogPrintExit2 warning $0 ("The changelog failed to run!") false; $LogPrint warning $0 ("The changelog failed to run!");
} }
} else={ } else={
$LogPrintExit2 warning $0 ("The changelog failed syntax validation!") false; $LogPrint warning $0 ("The changelog failed syntax validation!");
} }
} }
@ -1115,14 +1133,14 @@
:local Migration ($GlobalConfigMigration->[ :tostr $I ]); :local Migration ($GlobalConfigMigration->[ :tostr $I ]);
:if ([ :typeof $Migration ] = "str") do={ :if ([ :typeof $Migration ] = "str") do={
:if ([ $ValidateSyntax $Migration ] = true) 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 { :do {
[ :parse $Migration ]; [ :parse $Migration ];
} on-error={ } 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={ } else={
$LogPrintExit2 warning $0 ("Migration code for change " . $I . " failed syntax validation!") false; $LogPrint warning $0 ("Migration code for change " . $I . " failed syntax validation!");
} }
} }
} }
@ -1131,7 +1149,7 @@
:local NotificationMessage ("The configuration version on " . $Identity . " increased " . \ :local NotificationMessage ("The configuration version on " . $Identity . " increased " . \
"to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \ "to " . $ExpectedConfigVersion . ", current configuration may need modification. " . \
"Please review and update global-config-overlay, then re-run global-config."); "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={ :if ([ :len $GlobalConfigChanges ] > 0) do={
:set NotificationMessage ($NotificationMessage . "\n\nChanges:"); :set NotificationMessage ($NotificationMessage . "\n\nChanges:");
@ -1139,7 +1157,7 @@
:local Change ($GlobalConfigChanges->[ :tostr $I ]); :local Change ($GlobalConfigChanges->[ :tostr $I ]);
:set NotificationMessage ($NotificationMessage . "\n " . \ :set NotificationMessage ($NotificationMessage . "\n " . \
[ $SymbolForNotification "pushpin" "*" ] . $Change); [ $SymbolForNotification "pushpin" "*" ] . $Change);
$LogPrintExit2 info $0 ("Change " . $I . ": " . $Change) false; $LogPrint info $0 ("Change " . $I . ": " . $Change);
} }
} else={ } else={
:set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available."); :set NotificationMessage ($NotificationMessage . "\n\nNews and changes are not available.");
@ -1169,12 +1187,11 @@
# lock script against multiple invocation # lock script against multiple invocation
:set ScriptLock do={ :set ScriptLock do={
:local Script [ :tostr $1 ]; :local Script [ :tostr $1 ];
:local DoReturn $2; :local WaitMax ([ :tonum $3 ] * 10);
:local WaitMax ([ :tonum $3 ] * 10);
:global GetRandom20CharAlNum; :global GetRandom20CharAlNum;
:global IfThenElse; :global IfThenElse;
:global LogPrintExit2; :global LogPrint;
:global ScriptLockOrder; :global ScriptLockOrder;
:if ([ :typeof $ScriptLockOrder ] = "nothing") do={ :if ([ :typeof $ScriptLockOrder ] = "nothing") do={
@ -1260,15 +1277,17 @@
} }
:if ([ :len [ /system/script/find where name=$Script ] ] = 0) do={ :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={ :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={ :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) ({}); :set ($ScriptLockOrder->$Script) ({});
/system/script/job/remove [ find where script=$Script ]; /system/script/job/remove [ find where script=$Script ];
} }
@ -1285,13 +1304,13 @@
:if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={ :if ([ $IsFirstTicket $Script $MyTicket ] = true && [ $TicketCount $Script ] = [ $JobCount $Script ]) do={
$RemoveTicket $Script $MyTicket; $RemoveTicket $Script $MyTicket;
$CleanupTickets $Script; $CleanupTickets $Script;
:return false; :return true;
} }
$RemoveTicket $Script $MyTicket; $RemoveTicket $Script $MyTicket;
$LogPrintExit2 info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \ $LogPrint info $0 ("Script '" . $Script . "' started more than once" . [ $IfThenElse ($WaitCount > 0) \
" and timed out waiting for lock" "" ] . "... Aborting.") [ $IfThenElse ($DoReturn = true) false true ]; " and timed out waiting for lock" "" ] . "...");
:return true; :return false;
} }
# send notification via NotificationFunctions - expects at least two string arguments # send notification via NotificationFunctions - expects at least two string arguments
@ -1354,7 +1373,7 @@
} }
:if ([ :len ($Symbols->$Name) ] = 0) do={ :if ([ :len ($Symbols->$Name) ] = 0) do={
$LogPrintOnce warning $0 ("No symbol available for name '" . $Name . "'!") false; $LogPrintOnce warning $0 ("No symbol available for name '" . $Name . "'!");
:return ""; :return "";
} }
@ -1525,17 +1544,17 @@
:do { :do {
/system/script/run $Script; /system/script/run $Script;
} on-error={ } on-error={
$LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.") false; $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed to run.");
} }
} else={ } else={
$LogPrintExit2 error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.") false; $LogPrint error $0 ("Module '" . $ScriptVal->"name" . "' failed syntax validation, skipping.");
} }
} }
# Log success # Log success
:local Resource [ /system/resource/get ]; :local Resource [ /system/resource/get ];
$LogPrintOnce info $0 ("Loaded on " . $Resource->"board-name" . \ $LogPrintOnce info $ScriptName ("Loaded on " . $Resource->"board-name" . \
" with RouterOS " . $Resource->"version" . ".") false; " with RouterOS " . $Resource->"version" . ".");
# signal we are ready # signal we are ready
:set GlobalFunctionsReady true; :set GlobalFunctionsReady true;

View file

@ -8,6 +8,5 @@
# wait for global-functions to finish # wait for global-functions to finish
# https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/global-wait.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }

View file

@ -8,38 +8,43 @@
# track gps data by sending json data to http server # track gps data by sending json data to http server
# https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md # https://git.eworm.de/cgit/routeros-scripts/about/doc/gps-track.md
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global GpsTrackUrl; :do {
:global Identity; :local ScriptName [ :jobname ];
:global LogPrintExit2; :global GpsTrackUrl;
:global ScriptLock; :global Identity;
:global WaitFullyConnected;
$ScriptLock $0; :global LogPrint;
$WaitFullyConnected; :global ScriptLock;
:global WaitFullyConnected;
:local CoordinateFormat [ /system/gps/get coordinate-format ]; :if ([ $ScriptLock $ScriptName ] = false) do={
:local Gps [ /system/gps/monitor once as-value ]; :error false;
: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;
$LogPrintExit2 debug $0 ("Sending GPS data in " . $CoordinateFormat . " format: " . \
"lat: " . ($Gps->"latitude") . " " . \
"lon: " . ($Gps->"longitude")) false;
} on-error={
$LogPrintExit2 warning $0 ("Failed sending GPS data!") false;
} }
} else={ $WaitFullyConnected;
$LogPrintExit2 debug $0 ("GPS data not valid.") false;
} :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={ }

View file

@ -11,59 +11,64 @@
# #
# !! Do not edit this file, it is generated from template! # !! Do not edit this file, it is generated from template!
:local 0 [ :jobname ];
:global GlobalFunctionsReady; :global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:global EitherOr; :do {
:global LogPrintExit2; :local ScriptName [ :jobname ];
:global ParseKeyValueStore;
:global ScriptLock;
$ScriptLock $0 false 10; :global EitherOr;
:global LogPrint;
:global ParseKeyValueStore;
:global ScriptLock;
:local DHCPServers ({}); :if ([ $ScriptLock $ScriptName 10 ] = false) do={
:foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={ :error false;
: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 DHCPServers ({});
:local ClientVal [ /caps-man/registration-table/get $Client ]; :foreach Server in=[ /ip/dhcp-server/find where comment~"hotspot-to-wpa" ] do={
:foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \ :local ServerVal [ /ip/dhcp-server/get $Server ]
mac-address=($ClientVal->"mac-address") ] do={ :local ServerInfo [ $ParseKeyValueStore ($ServerVal->"comment") ];
:if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={ :if (($ServerInfo->"hotspot-to-wpa") = "wpa") do={
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ :set ($DHCPServers->($ServerVal->"name")) \
" connected to WPA, making lease static.") false; [ :totime [ $EitherOr ($ServerInfo->"timeout") 4w ] ];
/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=[ /caps-man/registration-table/find where comment~"^hotspot-to-wpa:" ] do={
!(comment~[ /system/clock/get date ]) ] do={ :local ClientVal [ /caps-man/registration-table/get $Client ];
:local ClientVal [ /caps-man/access-list/get $Client ]; :foreach Lease in=[ /ip/dhcp-server/lease/find where dynamic \
:if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \ mac-address=($ClientVal->"mac-address") ] do={
mac-address=($ClientVal->"mac-address") ] ] = 0) do={ :if (($DHCPServers->[ /ip/dhcp-server/lease/get $Lease server ]) > 0s) do={
$LogPrintExit2 info $0 ("Client with mac address " . ($ClientVal->"mac-address") . \ $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \
" did not connect to WPA, removing from access list.") false; " connected to WPA, making lease static.");
/caps-man/access-list/remove $Client; /ip/dhcp-server/lease/make-static $Lease;
/ip/dhcp-server/lease/set comment=($ClientVal->"comment") $Lease;
}
}
} }
}
:foreach Server,Timeout in=$DHCPServers do={ :foreach Client in=[ /caps-man/access-list/find where comment~"^hotspot-to-wpa:" \
:foreach Lease in=[ /ip/dhcp-server/lease/find where !dynamic status="waiting" \ !(comment~[ /system/clock/get date ]) ] do={
server=$Server last-seen>$Timeout comment~"^hotspot-to-wpa:" ] do={ :local ClientVal [ /caps-man/access-list/get $Client ];
:local LeaseVal [ /ip/dhcp-server/lease/get $Lease ]; :if ([ :len [ /ip/dhcp-server/lease/find where !dynamic comment~"^hotspot-to-wpa:" \
$LogPrintExit2 info $0 ("Client with mac address " . ($LeaseVal->"mac-address") . \ mac-address=($ClientVal->"mac-address") ] ] = 0) do={
" was not seen for " . ($LeaseVal->"last-seen") . ", removing.") false; $LogPrint info $ScriptName ("Client with mac address " . ($ClientVal->"mac-address") . \
/caps-man/access-list/remove [ find where comment~"^hotspot-to-wpa:" \ " did not connect to WPA, removing from access list.");
mac-address=($LeaseVal->"mac-address") ]; /caps-man/access-list/remove $Client;
/ip/dhcp-server/lease/remove $Lease; }
} }
}
: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={ }

Some files were not shown because too many files have changed in this diff Show more